2
0
mirror of https://github.com/boostorg/python.git synced 2026-01-30 20:12:37 +00:00

Initial revision

[SVN r1471]
This commit is contained in:
Raoul Gough
2003-09-03 20:47:11 +00:00
parent 6b988f72d8
commit b7ae3540e2
16 changed files with 2774 additions and 0 deletions

View File

@@ -0,0 +1,21 @@
container_proxy.hpp Container wrapper with semi-transparent proxies
shared_proxy_impl.hpp Component shared by proxies that refer to same element
testcontprox.cpp Simple tests for container_proxy
testindexing.py Test various instantiations of the indexing_suite
indexing.cpp Python extensions required for testindexing.py
vis.hpp.patch Simple vector_indexing_suite.hpp patch for indexing.cpp
sample.out Sample output of testindexing.py
vector_indexing_suite_ext.cpp Modified extension module from python/test
vector_indexing_suite.py Python test script from python/test (unmodified)
older stuff
===========
container_suite.hpp Container traits
iterator_suite.hpp Traits for iterator ranges
suite_utils.hpp Traits utilities
indexing_suite.cpp Traits tests
containers.txt Analysis of Python sequence vs. C++ containers
testlist.py Test behaviour of real Python lists

View File

@@ -0,0 +1,576 @@
// -*- mode:c++; switch-modules-target: "testcontprox.cpp" -*-
//
// Header file container_proxy.hpp
//
// Copyright (c) 2003 Raoul M. Gough
//
// This material is provided "as is", with absolutely no warranty expressed
// or implied. Any use is at your own risk.
//
// Permission to use or copy this material for any purpose is hereby
// granted without fee, provided the above notices are retained on all
// copies. Permission to modify the material and to distribute modified
// versions is granted, provided the above notices are retained, and a
// notice that the material was modified is included with the above
// copyright notice.
//
// History
// =======
// 2003/ 8/26 rmg File creation
//
// $Id$
//
#ifndef container_proxy_rmg_20030826_included
#define container_proxy_rmg_20030826_included
#include "shared_proxy_impl.hpp"
#include <map>
#include <memory>
#include <cassert>
#include <iterator>
#include <boost/shared_ptr.hpp>
template<typename T> struct identity {
static T & get(T & obj) { return obj; }
static T const & get(T const & obj) { return obj; }
};
template<typename T> struct deref {
template<typename U> static T & get (U & ptr) { return *ptr; }
template<typename U> static T const & get (U const & ptr) { return *ptr; }
};
template<class Container
, typename HeldType = Container
, class Accessor = identity<Container> >
class container_proxy
{
typedef container_proxy<Container, HeldType, Accessor> self_type;
typedef typename Container::iterator raw_iterator;
typedef std::iterator_traits<raw_iterator> raw_iterator_traits;
public:
typedef typename Container::size_type size_type;
typedef typename Container::difference_type difference_type;
typedef shared_proxy_impl<self_type> shared_proxy;
typedef typename Container::value_type raw_value_type;
struct const_element_proxy;
class element_proxy
{
friend class const_element_proxy;
typedef shared_proxy proxy_type;
typedef boost::shared_ptr<proxy_type> proxy_pointer;
proxy_pointer mPtr;
public:
typedef typename proxy_type::value_type value_type;
typedef typename proxy_type::reference reference;
typedef typename proxy_type::pointer pointer;
typedef typename proxy_type::iterator_category iterator_category;
typedef typename proxy_type::difference_type difference_type;
typedef value_type element_type; // Alias for register_ptr_to_python
element_proxy () : mPtr () { }
explicit element_proxy (proxy_type *ptr) : mPtr (ptr) { }
element_proxy (proxy_pointer const &ptr) : mPtr (ptr) { }
explicit element_proxy (raw_value_type const &val)
: mPtr (new proxy_type(val))
{
// Create new standalone value (i.e. detached)
}
reference operator* () const { return mPtr->operator*(); }
pointer operator-> () const { return (*mPtr).operator->(); }
pointer get () const { return operator->(); } // Alias for pointer_holder
// Implicit conversion to raw_value_type
operator reference () const { return operator*(); }
// These are necessary (at least) while the indexing suite insists
// on converting the real container's value_type to the proxy
// container's value_type when going from Python to C++. If the
// suite would just pass the real container's value_type through,
// our implicit conversion to value_type might suffice.
bool operator== (value_type const &other) { return (**this) == other; }
bool operator!= (value_type const &other) { return (**this) != other; }
bool operator< (value_type const &other) { return (**this) < other; }
bool operator> (value_type const &other) { return (**this) > other; }
element_proxy &operator= (value_type const &copy)
{
proxy_type &proxy (*mPtr);
container_proxy *container = proxy.owner();
size_type index = proxy.index();
if (container)
{
container->replace (index, copy);
// Proxy was attached before, but is now detached. Make sure
// we now refer to the new element, instead of the detached
// copy of the old element
mPtr = container->at (index).mPtr;
// Note: in the special case that this we and the container
// proxy itself have the only references to the
// shared_proxy_impl, it is not necessary to first detach
// the proxy. Maybe best to implement when changing to
// intrusive_ptr instead of shared_ptr.
}
else
{
*proxy = copy;
}
return *this;
}
element_proxy &operator= (element_proxy const &copy)
{
// This is the most dubious bit of the fudge. The indexing_suite's
// implementation of __setitem__ tries to pass us our value_type,
// which is actually of type element_proxy
return (*this) = *copy;
}
size_t use_count() const { return mPtr.use_count(); } // For debugging
};
struct const_element_proxy
{
typedef shared_proxy proxy_type;
typedef boost::shared_ptr<proxy_type> proxy_pointer;
proxy_pointer mPtr;
public:
typedef typename proxy_type::value_type const value_type;
typedef value_type &reference;
typedef value_type *pointer;
typedef typename proxy_type::iterator_category iterator_category;
typedef typename proxy_type::difference_type difference_type;
const_element_proxy () : mPtr () { }
explicit const_element_proxy (proxy_type *ptr) : mPtr (ptr) { }
const_element_proxy (proxy_pointer const &ptr) : mPtr (ptr) { }
const_element_proxy (element_proxy const &copy) : mPtr (copy.mPtr) { }
explicit const_element_proxy (raw_value_type const &val)
: mPtr (new proxy_type(val))
{
// Create new standalone value (i.e. detached)
}
reference operator* () const { return mPtr->operator*(); }
pointer operator-> () const { return mPtr->operator->(); }
// Implicit conversion to raw_value_type
operator reference () const { return operator*(); }
size_t use_count() const { return mPtr.use_count(); } // For debugging
};
typedef element_proxy value_type;
typedef element_proxy reference; // Already has reference semantics
typedef const_element_proxy const_value_type;
public:
struct iterator
{
typedef typename raw_iterator_traits::difference_type difference_type;
typedef std::random_access_iterator_tag iterator_category;
typedef element_proxy value_type;
typedef element_proxy *pointer;
typedef element_proxy reference; // Already has reference semantics
iterator (container_proxy *p, size_type i) : ptr (p), index (i) { }
iterator (container_proxy *p, raw_iterator iter)
: ptr (p), index (iter - p->container().begin())
{
}
reference operator*() const { return ptr->at(index); }
pointer operator->() const { return &ptr->at(index); }
reference operator[](size_type s) { return ptr->at (index + s); }
iterator &operator++ () { ++index; return *this; }
iterator &operator++ (int) { ++index; return *this; }
iterator &operator+= (size_type s) { index += s; return *this; }
iterator &operator-- () { --index; return *this; }
iterator &operator-- (int) { --index; return *this; }
iterator &operator-= (size_type s) { index -= s; return *this; }
iterator operator+ (size_type s) const { return iterator(*this) += s; }
iterator operator- (size_type s) const { return iterator(*this) -= s; }
difference_type operator- (iterator i) const { return index - i.index; }
bool operator== (iterator const &other) const {
return (ptr == other.ptr) && (index == other.index);
}
bool operator!= (iterator const &other) const { return !(*this == other); }
// public:
// Extensions to the normal iterator interface
// void replace (value_type const &copy) { ptr->replace (index, copy); }
public:
friend class container_proxy;
container_proxy *ptr;
size_type index;
};
public:
// Constructors
container_proxy ();
explicit container_proxy (HeldType const &h);
template<typename Iter> container_proxy (Iter, Iter);
Container & container(); // Should be private?
Container const &container() const; // Should be private?
element_proxy at (size_type index);
const_element_proxy at (size_type index) const;
element_proxy operator[] (size_type index) { return at(index); }
const_element_proxy operator[] (size_type index) const { return at(index); }
size_type size() const { return container().size(); }
size_type capacity() const { return container().capacity(); }
void reserve(size_type s) { container().reserve(s); }
public:
iterator begin() { return iterator (this, 0); }
iterator end() { return iterator (this, container().size()); }
iterator erase (iterator);
iterator erase (iterator, iterator);
iterator insert (iterator, raw_value_type const &);
template<typename Iter> void insert (iterator, Iter, Iter);
void push_back (raw_value_type const &copy) { insert (end(), copy); }
element_proxy pop_back () {
element_proxy result = at (end() - 1);
erase (end() - 1);
return result;
}
public:
// Proxies for a given index must be detached before overwriting
// that container element.
void detach_proxy (size_type index);
void detach_proxies (size_type from, size_type to);
void detach_proxies (iterator from, iterator to);
public:
// Convenient replacement of elements (automatic proxy detachment)
void replace (size_type index, raw_value_type const &);
template<typename Iter> void replace (size_type index, Iter, Iter);
private:
// Overloads for insertions with/without useful std::distance
template<typename Iter>
void insert (iterator, Iter, Iter, std::forward_iterator_tag);
template<typename Iter>
void insert (iterator, Iter, Iter, std::input_iterator_tag);
private:
typedef boost::shared_ptr<shared_proxy> pointer_impl;
typedef std::map<size_type, pointer_impl> MapType;
typedef typename MapType::iterator MapIterator;
typedef typename MapType::value_type MapEntry;
private:
static void detach_if_shared (MapEntry const &);
void adjustIndexes (MapIterator, MapIterator, long);
private:
HeldType myHeldType;
MapType myMap;
};
template<class Container, typename HeldType, class Accessor>
container_proxy<Container, HeldType, Accessor>
::container_proxy ()
: myHeldType ()
, myMap ()
{
}
template<class Container, typename HeldType, class Accessor>
container_proxy<Container, HeldType, Accessor>
::container_proxy (HeldType const &heldType)
: myHeldType (heldType)
, myMap ()
{
}
template<class Container, typename HeldType, class Accessor>
template<typename Iter>
container_proxy<Container, HeldType, Accessor>
::container_proxy (Iter start, Iter finish)
: myHeldType ()
, myMap ()
{
insert (begin(), start, finish);
}
template<class Container, typename HeldType, class Accessor>
Container &
container_proxy<Container, HeldType, Accessor>
::container ()
{
return Accessor::get (myHeldType);
}
template<class Container, typename HeldType, class Accessor>
Container const &
container_proxy<Container, HeldType, Accessor>
::container () const
{
return Accessor::get (myHeldType);
}
template<class Container, typename HeldType, class Accessor>
typename container_proxy<Container, HeldType, Accessor>::element_proxy
container_proxy<Container, HeldType, Accessor>
::at (size_type index)
{
pointer_impl &entry = myMap[index];
if (!entry.get())
{
entry.reset (new shared_proxy (this, index));
}
return element_proxy (entry);
}
template<class Container, typename HeldType, class Accessor>
typename container_proxy<Container, HeldType, Accessor>::const_element_proxy
container_proxy<Container, HeldType, Accessor>
::at (size_type index) const
{
// const_cast allows insertion into map. Maybe this is wrong, and
// there can be no const-version of at. Alternatively, maybe
// the map member variable should be declared mutable.
container_proxy *mutable_this = const_cast<container_proxy *>(this);
return const_element_proxy (mutable_this->at (index));
}
template<class Container, typename HeldType, class Accessor>
void
container_proxy<Container, HeldType, Accessor>
::replace (size_type index, raw_value_type const &copy)
{
detach_proxy (index);
container().at(index) = copy;
}
template<class Container, typename HeldType, class Accessor>
template<typename Iter>
void
container_proxy<Container, HeldType, Accessor>
::replace (size_type index, Iter from, Iter to)
{
while (from != to)
{
replace (index++, *from++);
}
}
template<class Container, typename HeldType, class Accessor>
typename container_proxy<Container, HeldType, Accessor>::iterator
container_proxy<Container, HeldType, Accessor>
::erase (iterator iter)
{
return erase (iter, iter + 1);
}
template<class Container, typename HeldType, class Accessor>
typename container_proxy<Container, HeldType, Accessor>::iterator
container_proxy<Container, HeldType, Accessor>
::erase (iterator from, iterator to)
{
assert (from.ptr == this);
assert (to.ptr == this);
size_type deleting = to.index - from.index;
MapIterator erase_begin = myMap.lower_bound (from.index);
MapIterator erase_end = myMap.lower_bound (to.index);
// Detach any proxies for the soon-to-be-erased elements
std::for_each (erase_begin, erase_end, detach_if_shared);
myMap.erase (erase_begin, erase_end); // Note: erase_end remains valid
// Adjust the indexes of any following proxies
adjustIndexes (erase_end, myMap.end(), -deleting);
// Erase the elements from the real container
raw_iterator result = container().erase (container().begin() + from.index
, container().begin() + to.index);
return iterator (this, result);
}
template<class Container, typename HeldType, class Accessor>
typename container_proxy<Container, HeldType, Accessor>::iterator
container_proxy<Container, HeldType, Accessor>
::insert (iterator iter, raw_value_type const &copy)
{
assert (iter.ptr == this);
// Adjust indexes from iter.index, since insert will go before iter
adjustIndexes (myMap.lower_bound (iter.index), myMap.end(), 1);
// Insert the element into the real container
raw_iterator result = container().insert (container().begin() + iter.index
, copy);
return iterator (this, result);
}
template<class Container, typename HeldType, class Accessor>
template<typename Iter>
void
container_proxy<Container, HeldType, Accessor>
::insert (iterator iter, Iter from, Iter to)
{
// Forward insertion to the right overloaded version
typedef typename std::iterator_traits<Iter>::iterator_category category;
insert (iter, from, to, category());
}
template<class Container, typename HeldType, class Accessor>
template<typename Iter>
void
container_proxy<Container, HeldType, Accessor>
::insert (iterator iter, Iter from, Iter to, std::forward_iterator_tag)
{
// insert overload for iterators where we can get distance()
assert (iter.ptr == this);
// Adjust indexes from iter.index, since insert will go before iter
adjustIndexes (myMap.lower_bound (iter.index)
, myMap.end()
, std::distance (from, to));
// Insert the element into the real container
container().insert (container().begin() + iter.index, from, to);
}
template<class Container, typename HeldType, class Accessor>
template<typename Iter>
void
container_proxy<Container, HeldType, Accessor>
::insert (iterator iter, Iter from, Iter to, std::input_iterator_tag)
{
// insert overload for iterators where we *can't* get distance()
// so just insert elements one at a time
while (from != to)
{
iter = insert (iter, *from++) + 1;
}
}
template<class Container, typename HeldType, class Accessor>
void
container_proxy<Container, HeldType, Accessor>
::detach_if_shared (MapEntry const &ent)
{
if (!ent.second.unique())
{
ent.second->detach();
}
// If the pointer isn't shared, don't bother causing a copy of the
// container element, since the proxy is about to be deleted.
}
template<class Container, typename HeldType, class Accessor>
void
container_proxy<Container, HeldType, Accessor>
::detach_proxy (size_type index)
{
MapIterator iter = myMap.find (index);
if (iter != myMap.end())
{
detach_if_shared (*iter);
myMap.erase (iter);
}
}
template<class Container, typename HeldType, class Accessor>
void
container_proxy<Container, HeldType, Accessor>
::detach_proxies (size_type fromIndex, size_type toIndex)
{
MapIterator from = myMap.lower_bound (fromIndex);
MapIterator to = myMap.lower_bound (toIndex);
std::for_each (from, to, detach_if_shared);
myMap.erase (from, to);
}
template<class Container, typename HeldType, class Accessor>
void
container_proxy<Container, HeldType, Accessor>
::detach_proxies (iterator from, iterator to)
{
assert (from.ptr == this);
assert (to.ptr == this);
detach_proxies (from.index, to.index);
}
template<class Container, typename HeldType, class Accessor>
void
container_proxy<Container, HeldType, Accessor>
::adjustIndexes (MapIterator from, MapIterator to, long offset)
{
// Adjust indexes in the given range of proxies by the given offset.
// The adjustment is done by erasing and re-inserting the entries
// in the map.
//
// Could provide a hint iterator to the map insertion calls, except
// in the case that "from" is right at the start of the container
// (the hint must be the element *before* the one to be inserted,
// and there is no element before the first one). This would mean
// additional complexity to deal with the special case somehow.
while (from != to)
{
MapIterator next (from);
++next; // Find next element before invalidating the current one
pointer_impl ptr (from->second); // Copy the shared pointer
myMap.erase (from); // Remove the map copy of it
if (!ptr.unique())
{
// Reinsert only if there are other pointers "out there"
// referring to the shared proxy
ptr->myIndex += offset;
myMap.insert (typename MapType::value_type (ptr->myIndex, ptr));
}
from = next;
}
}
#endif // container_proxy_rmg_20030826_included

View File

@@ -0,0 +1,349 @@
// -*- mode:c++ -*-
//
// Header file container_suite.hpp
//
// Copyright (c) 2003 Raoul M. Gough
//
// This material is provided "as is", with absolutely no warranty expressed
// or implied. Any use is at your own risk.
//
// Permission to use or copy this material for any purpose is hereby
// granted without fee, provided the above notices are retained on all
// copies. Permission to modify the material and to distribute modified
// versions is granted, provided the above notices are retained, and a
// notice that the material was modified is included with the above
// copyright notice.
//
// History
// =======
// 2003/ 8/23 rmg File creation
//
// $Id$
//
#ifndef container_suite_rmg_20030823_included
#define container_suite_rmg_20030823_included
#include "suite_utils.hpp"
#include "iterator_suite.hpp"
#include <boost/type_traits.hpp>
#include <set>
#include <map>
#include <list>
#include <deque>
#include <vector>
namespace indexing {
//////////////////////////////////////////////////////////////////////////
// Iterator pair container emulation
//////////////////////////////////////////////////////////////////////////
template<typename Iterator>
class iterator_pair
{
private:
typedef typename boost::call_traits<Iterator>::param_type iterator_param;
typedef std::iterator_traits<Iterator> std_traits;
public:
typedef typename std_traits::reference reference;
typedef Iterator iterator;
typedef typename std_traits::difference_type size_type;
typedef typename std_traits::difference_type difference_type;
typedef typename std_traits::value_type value_type;
typedef typename std_traits::pointer pointer;
// Can't provide: const_iterator, allocator_type, reverse_iterator
// or const_reverse_iterator. Could probably provide (but don't)
// const_reference and const_pointer. These would be the same
// as reference and pointer if Iterator is itself a const_iterator.
public:
iterator_pair (iterator_param, iterator_param);
iterator begin() const;
iterator end() const;
public:
// Only sensible for random_access iterators
size_type size () const;
reference operator[] (size_type) const;
private:
iterator myBegin;
iterator myEnd;
};
template<typename Iterator>
iterator_pair<Iterator>::iterator_pair (iterator_param begin
, iterator_param end)
: myBegin (begin)
, myEnd (end)
{
}
template<typename Iterator>
typename iterator_pair<Iterator>::iterator
iterator_pair<Iterator>::begin() const
{
return myBegin;
}
template<typename Iterator>
typename iterator_pair<Iterator>::iterator
iterator_pair<Iterator>::end() const
{
return myEnd;
}
template<typename Iterator>
typename iterator_pair<Iterator>::size_type
iterator_pair<Iterator>::size() const
{
return std::distance (begin(), end());
}
template<typename Iterator>
typename iterator_pair<Iterator>::reference
iterator_pair<Iterator>::operator[](size_type index) const
{
return *(begin() + index);
}
/////////////////////////////////////////////////////////////////////////
// Container traits
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
// Traits for the iterator_pair container emulator
/////////////////////////////////////////////////////////////////////////
template<typename IteratorPair>
struct iterator_pair_traits
: public
iterator_detail::traits_by_category<typename IteratorPair::iterator>::type
{
typedef IteratorPair container;
typedef typename IteratorPair::size_type size_type;
typedef typename IteratorPair::size_type index_type; // at()
static bool const has_insert = false;
static bool const has_erase = false;
static bool const has_pop_back = false;
static bool const has_push_back = false;
// Default implementations of support functions
typedef container_algorithms<iterator_pair_traits> algorithms;
};
/////////////////////////////////////////////////////////////////////////
// Lowest common denominator (almost all "real" containers would
// meet at least these requirements)
/////////////////////////////////////////////////////////////////////////
template<typename Container>
struct default_container_traits
{
protected:
static bool const is_mutable = ! boost::is_const<Container>::value;
public:
typedef Container container;
typedef typename Container::value_type value_type;
typedef typename Container::reference reference;
typedef typename Container::difference_type difference_type;
typedef typename Container::size_type size_type;
typedef typename Container::size_type index_type; // at()
typedef value_type key_type; // find, count, ...
// Should probably select iterator or const_iterator on the
// basis of is_mutable
typedef typename Container::iterator iterator;
typedef typename Container::const_iterator const_iterator;
static bool const has_copyable_iter = true;
static bool const has_random_access
= ::indexing::iterator_traits<iterator>::has_random_access;
static bool const has_mutable_ref
= is_mutable && is_mutable_ref<reference>::value;
// has_mutable_ref basically means that the container supports
// in-place replacement of values (e.g. the associative containers
// *don't*)
static bool const is_reversible = has_mutable_ref;
static bool const has_insert = is_mutable;
static bool const has_erase = is_mutable;
static bool const has_pop_back = false;
static bool const has_push_back = false;
// Default implementations of support functions
typedef container_algorithms<default_container_traits> algorithms;
};
/////////////////////////////////////////////////////////////////////////
// Sequences (list, deque, vector)
/////////////////////////////////////////////////////////////////////////
template<typename Container>
struct default_sequence_traits : public default_container_traits<Container>
{
static bool const has_pop_back = is_mutable;
static bool const has_push_back = is_mutable;
};
template<typename Container>
struct list_traits : public default_sequence_traits<Container>
{
// Some special algo's for list (using member functions)
typedef list_algorithms<list_traits> algorithms;
};
/////////////////////////////////////////////////////////////////////////
// Associative containers set and multiset
/////////////////////////////////////////////////////////////////////////
template<typename Container>
struct set_traits : public default_container_traits<Container>
{
// Special algo's for set types (using member functions)
typedef assoc_algorithms<set_traits> algorithms;
};
/////////////////////////////////////////////////////////////////////////
// Associative containers map and multimap
/////////////////////////////////////////////////////////////////////////
template<typename Container>
struct map_traits : public default_container_traits<Container>
{
typedef typename Container::key_type key_type; // find, count, ...
// Special algo's for map types (using member functions)
typedef assoc_algorithms<map_traits> algorithms;
};
/////////////////////////////////////////////////////////////////////////
// Automated trait selection
/////////////////////////////////////////////////////////////////////////
namespace container_details {
template<typename Container> struct traits_by_type;
// traits_by_type instances should include two typedefs, one for
// the non-const version of the container, and one for the
// const version. This saves having to have two specializations
// of traits_by_type for every kind of container.
// std::set
template <class Key, class Compare, class Allocator>
class traits_by_type<std::set<Key, Compare, Allocator> >
{
typedef std::set<Key, Compare, Allocator> Container;
public:
typedef set_traits<Container> mutable_type;
typedef set_traits<Container const> const_type;
};
// std::multiset
template <class Key, class Compare, class Allocator>
class traits_by_type<std::multiset<Key, Compare, Allocator> >
{
typedef std::multiset<Key, Compare, Allocator> Container;
public:
typedef set_traits<Container> mutable_type;
typedef set_traits<Container const> const_type;
};
// std::map
template <class Key, class T, class Compare, class Allocator>
class traits_by_type<std::map<Key, T, Compare, Allocator> >
{
typedef std::map<Key, T, Compare, Allocator> Container;
public:
typedef map_traits<Container> mutable_type;
typedef map_traits<Container const> const_type;
};
// std::multimap
template <class Key, class T, class Compare, class Allocator>
class traits_by_type<std::multimap<Key, T, Compare, Allocator> >
{
typedef std::multimap<Key, T, Compare, Allocator> Container;
public:
typedef map_traits<Container> mutable_type;
typedef map_traits<Container const> const_type;
};
// std::vector
template <class T, class Allocator>
class traits_by_type<std::vector<T, Allocator> >
{
typedef std::vector<T, Allocator> Container;
public:
typedef default_sequence_traits<Container> mutable_type;
typedef default_sequence_traits<Container const> const_type;
};
// std::deque
template <class T, class Allocator>
class traits_by_type<std::deque<T, Allocator> >
{
typedef std::deque<T, Allocator> Container;
public:
typedef default_sequence_traits<Container> mutable_type;
typedef default_sequence_traits<Container const> const_type;
};
// std::list
template <class T, class Allocator>
class traits_by_type<std::list<T, Allocator> >
{
typedef std::list<T, Allocator> Container;
public:
typedef list_traits<Container> mutable_type;
typedef list_traits<Container const> const_type;
};
// Iterator ranges
template <typename Iterator>
class traits_by_type<indexing::iterator_pair<Iterator> >
{
typedef ::indexing::iterator_pair<Iterator> Container;
public:
typedef iterator_pair_traits<Container> mutable_type;
typedef iterator_pair_traits<Container const> const_type; // ?
};
}
// Select the right traits for each supported kind of container
// Generic version (mutable containers)
template<class Container>
struct container_traits
: public container_details::traits_by_type<Container>::mutable_type
{
};
// Partial specialization for const containers
template<class Container>
struct container_traits<Container const>
: public container_details::traits_by_type<Container>::const_type
{
};
}
#endif // container_suite_rmg_20030823_included

View File

@@ -0,0 +1,129 @@
Copyright (c) 2003 Raoul M. Gough
This material is provided "as is", with absolutely no warranty expressed
or implied. Any use is at your own risk.
Permission to use or copy this material for any purpose is hereby
granted without fee, provided the above notices are retained on all
copies. Permission to modify the material and to distribute modified
versions for any purpose is granted, provided the above notices are
retained, and a notice that the material was modified is included with
the above copyright notice.
$Id$
==============================================================================
This file contains information and comments about mapping Python
sequence functionality onto STL containers or iterator pairs. Primary
sources of information are the Python Library Reference, sections
2.2.6 (Sequence types) and 2.2.6.4 (Mutable sequence types), the
Python Reference Manual (aka Language Reference) sections 3.3 (Special
method names), 3.3.4 (Emulating container types) and 3.3.6 (Eumlating
numeric types) and the C++ standard (ISO/IEC 14882:1998(E)).
==============================================================================
Sequence functionality - Python expressions, the Python method used to
implement the operation (in order of preference) and possible C++
equivalents.
Python feature Implementation (preferential order) Possible C++ emulation
============== =================================== ======================
x in s __contains__, __iter__, __getitem__ find algo/member fn
x not in s __contains__, __iter__, __getitem__ find algo/member fn
s + t __add__ or __radd__ constr., insert [1]
s * n , n * s __mul__ or __rmul__ constr., insert [1]
s[i] __getitem__ [] or *(iter + i)
s[i:j] __getslice__ [3], __getitem__ constr(iter,iter)[2]
len(s) __len__ distance/size memfn
iter(s) __iter__ constr. iter pair
min(s) __iter__, __getitem__ (?)
max(s) __iter__, __getitem__ (?)
[1] have to construct new container (make vector from iterator pairs?)
[2] construct copy of container contents or return iterator pair?
[3] __getslice__, __setslice__ and __delslice__ are deprecated
Mutable sequence functionality:
Python feature Implementation (preferential order) Possible C++ emulation
============== =================================== ======================
s[i] = x __setitem__ s[i]=x or *(iter+i)=x
s[i:j] = t __setslice__ [3], __setitem__ operator=,insert,erase
del s[i:j] __delslice__ [3], __delitem__ erase
del s[i] __delitem__ erase
s += t __iadd__ insert(iter,iter)
s *= t __imul__ insert(iter,iter)
s.append(x) append insert(obj)
s.extend(x) extend [ python list type only ] insert(iter,iter)
s.count(x) count count algo/mem fn
s.index(x) index find algo/mem fn
s.insert(i, x) insert insert
s.pop([i]) pop pop_back/erase?
s.remove(x) remove remove_if and erase?
s.reverse() reverse reverse
s.sort([cmpfunc]) sort sort algo?
[3] __getslice__, __setslice__ and __delslice__ are deprecated
==============================================================================
Cross-reference. C++ functions for the various types of iterator-pair
ranges and the python methods that they can implement.
C++ functions Minimum iterator type Python function(s)
============= ===================== ==================
++, * input_iterator[4] next
copyable iterator forward_iterator[5] __iter__
std::distance forward_iterator[5] __len__
std::find forward_iterator[5] __contains__, index
std::count forward_iterator[5] count
std::reverse bidirectional_iter[6] reverse
+, * random_access_iter[4] __getitem__ [7]
+, non-const * random_access_iter[6] __setitem__(index)[8]
std::sort random_access_iter[6] sort([cmpfunc])
[4] iterator_traits<iterator>::reference can be reference to const
[5] input_iterator is unsuitable because copies aren't independant
[6] iterator_traits<iterator>::reference must not be reference to const
[7] maybe return an iterator pair if step is 1 or -1 (reverse_iterator)
[8] support slices where replacement sequence is of equal length?
Continued cross-reference. C++ functions for the various types of STL
containers and the python methods that they can implement.
C++ functions Minimum container type Python function(s)
============= ====================== ==================
insert any insert
member function size any(?) __len__
nonconst [] any except list __setitem__(index/key)
pop_back non-associative pop()
push_back non-associative append, __iadd__, __imul__
std::find, erase non-associative remove(value)
member function find associative __contains__
find, erase associative pop(key)
erase associative remove, __delitem__(key)
nonconst [], insert, erase vector, deque __setitem__(slice)
erase vector, deque pop(index), __delitem__
insert multimap, multiset __iadd__, __imul__
member function sort list sort
member function reverse list reverse
=============================================================================
random notes
============
What about __lt__, __le__, __ne__, __eq__, __ge__ and __gt__ ?
What about debugging? Maybe the traits classes need to identify
themselves, so that traits-clients could trace information about what
traits were used. Otherwise, if expected features aren't available,
how would the programmer figure out why not?

View File

@@ -0,0 +1,222 @@
// -*- mode:c++; switch-modules-target: "testindexing.py" -*-
//
// Module indexing.cpp
//
// Copyright (c) 2003 Raoul M. Gough
//
// This material is provided "as is", with absolutely no warranty expressed
// or implied. Any use is at your own risk.
//
// Permission to use or copy this software for any non-commercial purpose
// is hereby granted without fee, provided the above notices are retained
// on all copies. Permission to modify the code and to distribute
// modified code for non-commercial purposes is granted, provided the
// above notices are retained, and a notice that the code was modified is
// included with the above copyright notice.
//
// History
// =======
// 2003/ 8/18 rmg File creation
//
// $Id$
//
#include "container_proxy.hpp"
#include <boost/python/def.hpp>
#include <boost/python/class.hpp>
#include <boost/python/module.hpp>
#include <boost/python/implicit.hpp>
#include <boost/python/suite/indexing/indexing_suite.hpp>
#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
#include <boost/lexical_cast.hpp>
#include <string>
#include <vector>
namespace {
bool gIntWrapperTrace = true;
}
struct IntWrapper {
static unsigned ourObjectCounter;
int mObjNumber;
int mI;
IntWrapper ()
: mObjNumber (ourObjectCounter++)
, mI (0)
{
if (gIntWrapperTrace)
{
printf ("IntWrapper %u ()\n", mObjNumber);
}
}
explicit IntWrapper (int i)
: mObjNumber (ourObjectCounter++)
, mI (i)
{
if (gIntWrapperTrace)
{
printf ("IntWrapper %u (%d)\n"
, mObjNumber
, mI);
}
}
IntWrapper (IntWrapper const &other)
: mObjNumber (ourObjectCounter++)
, mI (other.mI)
{
if (gIntWrapperTrace)
{
printf ("IntWrapper %u (IntWrapper %u)\n"
, mObjNumber
, other.mObjNumber);
}
}
IntWrapper &operator= (IntWrapper const &other)
{
if (gIntWrapperTrace)
{
printf ("IntWrapper %u = IntWrapper %u\n"
, mObjNumber
, other.mObjNumber);
}
mI = other.mI;
return *this;
}
~IntWrapper ()
{
if (gIntWrapperTrace)
{
printf ("~IntWrapper %u\n", mObjNumber);
}
}
void increment()
{
if (gIntWrapperTrace)
{
printf ("IntWrapper %u::increment\n", mObjNumber);
}
++mI;
}
operator boost::shared_ptr<IntWrapper> () const
{
if (gIntWrapperTrace)
{
printf ("IntWrapper %u shared_ptr conversion\n", mObjNumber);
}
return boost::shared_ptr<IntWrapper> (new IntWrapper (*this));
}
};
unsigned IntWrapper::ourObjectCounter = 0;
bool operator== (IntWrapper const &lhs, IntWrapper const &rhs)
{
return lhs.mI == rhs.mI;
}
bool operator< (IntWrapper const &lhs, IntWrapper const &rhs)
{
return lhs.mI < rhs.mI;
}
std::ostream &operator<< (std::ostream &strm, IntWrapper const &iw)
{
strm << iw.mI;
return strm;
}
template<typename ContainerProxy>
std::string proxy_repr (typename ContainerProxy::value_type const &proxy)
{
return boost::lexical_cast<std::string, IntWrapper> (*proxy);
}
template<typename ContainerProxy>
void proxy_increment (typename ContainerProxy::value_type const &proxy)
{
(*proxy).increment();
}
std::string pointer_repr (boost::shared_ptr<IntWrapper> const &ptr)
{
return boost::lexical_cast<std::string, IntWrapper> (*ptr);
}
void pointer_increment (boost::shared_ptr<IntWrapper> const &ptr)
{
(*ptr).increment();
}
void setTrace (int onoff)
{
gIntWrapperTrace = onoff;
}
IntWrapper *get_pointer (container_proxy<std::vector<IntWrapper> >::value_type const &proxy)
{
return &(*proxy);
}
BOOST_PYTHON_MODULE (indexing)
{
boost::python::def ("trace", &setTrace);
typedef std::vector<IntWrapper> Container;
typedef container_proxy<Container> ProxyContainer;
typedef boost::shared_ptr<IntWrapper> Pointer;
typedef std::vector<Pointer> PointerContainer;
using boost::python::vector_indexing_suite;
// typedef vector_indexing_suite<Container, true> Suite;
typedef vector_indexing_suite<Container, false> ProxySuite;
typedef vector_indexing_suite<ProxyContainer, true> ProxyContainerSuite;
typedef vector_indexing_suite<PointerContainer, true> PointerContainerSuite;
boost::python::class_<Container> ("Vector")
.def (ProxySuite())
.def ("reserve", &Container::reserve);
boost::python::class_<ProxyContainer> ("ProxyVector")
.def (ProxyContainerSuite())
.def ("reserve", &ProxyContainer::reserve);
boost::python::class_<PointerContainer> ("PointerVector")
.def (PointerContainerSuite())
.def ("reserve", &PointerContainer::reserve);
boost::python::implicitly_convertible <IntWrapper, ProxyContainer::value_type>();
boost::python::class_<IntWrapper> ("IntWrapper", boost::python::init<int>())
.def ("increment", &IntWrapper::increment)
.def ("__repr__", &boost::lexical_cast<std::string, IntWrapper>)
;
// Ultimately, all of the value_type's properties should be provided
// via something like register_ptr_to_python with double-dereferencing.
// boost::python::class_<ProxyContainer::value_type> ("Container__value_type", boost::python::init<IntWrapper>())
// .def ("increment", proxy_increment<ProxyContainer>)
// .def ("__repr__", proxy_repr<ProxyContainer>)
// ;
boost::python::register_ptr_to_python<ProxyContainer::value_type>();
boost::python::implicitly_convertible <IntWrapper, Pointer>();
boost::python::class_<Pointer> ("Pointer", boost::python::no_init)
.def ("increment", pointer_increment)
.def ("__repr__", pointer_repr)
;
}

View File

@@ -0,0 +1,165 @@
// -*- mode:c++ -*-
//
// Module indexing_suite.cc
//
// Copyright (c) 2003 Raoul M. Gough
//
// This material is provided "as is", with absolutely no warranty expressed
// or implied. Any use is at your own risk.
//
// Permission to use or copy this material for any purpose is hereby
// granted without fee, provided the above notices are retained on all
// copies. Permission to modify the material and to distribute modified
// versions is granted, provided the above notices are retained, and a
// notice that the material was modified is included with the above
// copyright notice.
//
// History
// =======
// 2003/ 8/22 rmg File creation
//
// $Id$
//
#include "container_suite.hpp"
#include "iterator_suite.hpp"
#include <iterator>
#include <typeinfo>
#include <iostream>
#include <ostream>
#include <vector>
#include <deque>
#include <list>
#include <set>
#ifdef __GNUC__
#include <cxxabi.h>
static int DEMANGLE_STATUS = 0;
# define TYPENAME(t) \
abi::__cxa_demangle(typeid(t).name(), 0, 0, &DEMANGLE_STATUS)
#else
# define TYPENAME(t) \
typeid(t).name()
#endif // __GXX__
template<typename Traits>
void test ()
{
std::cout
<< TYPENAME(Traits)
<< "\n"
<< Traits::has_copyable_iter
<< " iterator_traits<T>::has_copyable_iter\n"
<< Traits::is_reversible
<< " iterator_traits<T>::is_reversible\n"
<< Traits::has_random_access
<< " iterator_traits<T>::has_random_access\n"
<< Traits::has_mutable_ref
<< " iterator_traits<T>::has_mutable_ref\n"
<< Traits::has_insert
<< " iterator_traits<T>::has_insert\n"
<< Traits::has_erase
<< " iterator_traits<T>::has_erase\n"
<< Traits::has_pop_back
<< " iterator_traits<T>::has_pop_back\n"
<< Traits::has_push_back
<< " iterator_traits<T>::has_push_back\n"
<< "=====================================\n"
;
}
int main ()
{
using indexing::iterator_traits;
using indexing::container_traits;
using indexing::iterator_pair;
test<container_traits <iterator_pair<std::istream_iterator<int> > > >();
test<container_traits <iterator_pair<std::set<int>::const_iterator> > >();
test<container_traits <iterator_pair<std::set<int>::iterator> > >();
test<container_traits <iterator_pair<std::list<int>::const_iterator> > >();
test<container_traits <iterator_pair<std::list<int>::iterator> > >();
test<container_traits <iterator_pair<std::deque<int>::const_iterator> > >();
test<container_traits <iterator_pair<std::deque<int>::iterator> > >();
test<container_traits <iterator_pair<std::vector<int>::const_iterator> > >();
test<container_traits <iterator_pair<std::vector<int>::iterator> > >();
test<container_traits <iterator_pair<int const *> > >();
test<container_traits <iterator_pair<int *> > >();
test<container_traits <std::list<int> > >();
test<container_traits <std::list<int> const> >();
test<container_traits <std::deque<int> > >();
test<container_traits <std::deque<int> const> >();
test<container_traits <std::vector<int> > >();
test<container_traits <std::vector<int> const> >();
test<container_traits <std::set<int> > >();
test<container_traits <std::set<int> const> >();
typedef iterator_pair<int *> Range;
int array[16] = {0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
Range range (array, array + 16);
container_traits<Range>::algorithms::reverse (range);
std::cout
<< *container_traits<Range>::algorithms::at (range, 0) << " "
<< *container_traits<Range>::algorithms::at (range, 1) << " "
<< *container_traits<Range>::algorithms::at (range, 2) << " "
<< "\n";
container_traits<Range>::algorithms::sort (range);
std::cout
<< *container_traits<Range>::algorithms::at (range, 3) << " "
<< *container_traits<Range>::algorithms::at (range, 4) << " "
<< *container_traits<Range>::algorithms::at (range, 5) << " "
<< "\n";
std::cout
<< container_traits<Range>::algorithms::size (range)
<< "\n"
<< container_traits<Range>::algorithms::find (range, 8) - array
<< "\n"
<< container_traits<Range>::algorithms::count (range, 0)
<< "\n"
;
typedef std::list<int> List;
List l (array, array + 16);
container_traits<List>::algorithms::reverse (l);
std::copy (l.begin(), l.end(), std::ostream_iterator<int>(std::cout, " "));
std::cout << "\n";
container_traits<List>::algorithms::sort (l);
std::copy (l.begin(), l.end(), std::ostream_iterator<int>(std::cout, " "));
std::cout << "\n";
typedef std::set<int> Set;
Set s (l.begin(), l.end());
std::cout
<< container_traits<Set>::algorithms::count (s, 0)
<< "\n"
<< *container_traits<Set>::algorithms::find (s, 8)
<< "\n"
;
typedef std::multiset<int> Multiset;
Multiset multi_s (l.begin(), l.end());
std::cout
<< container_traits<Multiset>::algorithms::count (multi_s, 0)
<< "\n"
<< *container_traits<Multiset>::algorithms::find (multi_s, 8)
<< "\n"
;
}

View File

@@ -0,0 +1,143 @@
// -*- mode:c++ -*-
//
// Header file iterator_suite.hpp
//
// Copyright (c) 2003 Raoul M. Gough
//
// This material is provided "as is", with absolutely no warranty expressed
// or implied. Any use is at your own risk.
//
// Permission to use or copy this material for any purpose is hereby
// granted without fee, provided the above notices are retained on all
// copies. Permission to modify the material and to distribute modified
// versions is granted, provided the above notices are retained, and a
// notice that the material was modified is included with the above
// copyright notice.
//
// History
// =======
// 2003/ 8/23 rmg File creation
//
// $Id$
//
#ifndef iterator_suite_rmg_20030823_included
#define iterator_suite_rmg_20030823_included
#include "suite_utils.hpp"
#include <iterator>
#include <boost/call_traits.hpp>
#include <boost/type_traits.hpp>
namespace indexing {
//////////////////////////////////////////////////////////////////////////
// Indexing traits for containers based on iterator pairs
//////////////////////////////////////////////////////////////////////////
template<typename Iterator>
struct input_iterator_traits
{
private:
typedef std::iterator_traits<Iterator> std_traits;
public:
typedef Iterator iterator;
typedef typename std_traits::value_type value_type;
typedef typename std_traits::reference reference;
typedef typename std_traits::difference_type difference_type;
typedef typename std_traits::difference_type index_type;
typedef value_type key_type; // find, count, ...
static bool const has_copyable_iter = false;
static bool const is_reversible = false;
static bool const has_random_access = false;
static bool const has_mutable_ref = is_mutable_ref<reference>::value;
};
template<typename Iterator>
struct forward_iterator_traits
: public input_iterator_traits<Iterator>
{
static bool const has_copyable_iter = true;
};
template<typename Iterator>
struct bidirectional_iterator_traits
: public forward_iterator_traits<Iterator>
{
static bool const is_reversible = has_mutable_ref;
};
template<typename Iterator>
struct random_access_iterator_traits
: public bidirectional_iterator_traits<Iterator>
{
static bool const has_random_access = true;
};
namespace iterator_detail {
typedef char input_iter_sizer[1];
typedef char forward_iter_sizer[2];
typedef char bidirectional_iter_sizer[3];
typedef char random_access_iter_sizer[4];
input_iter_sizer &sizer (std::input_iterator_tag const &);
forward_iter_sizer &sizer (std::forward_iterator_tag const &);
bidirectional_iter_sizer &sizer (std::bidirectional_iterator_tag const &);
random_access_iter_sizer &sizer (std::random_access_iterator_tag const &);
template<size_t Size> struct traits_by_size { };
template<>
struct traits_by_size<sizeof(input_iter_sizer)> {
template<typename Iterator>
struct traits {
typedef input_iterator_traits<Iterator> type;
};
};
template<>
struct traits_by_size<sizeof(forward_iter_sizer)> {
template<typename Iterator>
struct traits {
typedef forward_iterator_traits<Iterator> type;
};
};
template<>
struct traits_by_size<sizeof(bidirectional_iter_sizer)> {
template<typename Iterator>
struct traits {
typedef bidirectional_iterator_traits<Iterator> type;
};
};
template<>
struct traits_by_size<sizeof(random_access_iter_sizer)> {
template<typename Iterator>
struct traits {
typedef random_access_iterator_traits<Iterator> type;
};
};
template<typename Iterator>
class traits_by_category {
typedef typename std::iterator_traits<Iterator>::iterator_category
iterator_category;
static size_t const size = sizeof(sizer(iterator_category()));
public:
typedef typename traits_by_size<size>::traits<Iterator>::type type;
};
}
template<typename Iterator>
struct iterator_traits
: public iterator_detail::traits_by_category<Iterator>::type
{
};
}
#endif // iterator_suite_rmg_20030823_included

View File

@@ -0,0 +1,44 @@
<indexing.Vector object at 0x007B57E0>
1 2 3
1 2 3
copy is 2, v[1] is 2
copy is 3, v[1] is 3
copy is 5, v[1] is 5
slice[0] is 5, copy is 5, v[1] is 5
slice[0] is 5, copy is 5, v[1] is 6
slice[0] is 5, copy is 5, v[1] is 7
slice[0] is 9, copy is 9, v[1] is 7
=============
<indexing.ProxyVector object at 0x007B57E0>
1 2 3
1 2 3
copy is 2, v[1] is 2
copy is 3, v[1] is 3
copy is 3, v[1] is 5
slice[0] is 5, copy is 5, v[1] is 5
slice[0] is 5, copy is 5, v[1] is 6
slice[0] is 5, copy is 5, v[1] is 7
slice[0] is 9, copy is 5, v[1] is 7
=============
<indexing.PointerVector object at 0x007B57E0>
1 2 3
1 2 3
copy is 2, v[1] is 2
copy is 3, v[1] is 3
copy is 3, v[1] is 5
slice[0] is 5, copy is 5, v[1] is 5
slice[0] is 6, copy is 6, v[1] is 6
slice[0] is 6, copy is 6, v[1] is 7
slice[0] is 9, copy is 6, v[1] is 7
=============
[]
1 2 3
1 2 3
copy is 2, v[1] is 2
copy is 3, v[1] is 3
copy is 3, v[1] is 5
slice[0] is 5, copy is 5, v[1] is 5
slice[0] is 6, copy is 6, v[1] is 6
slice[0] is 6, copy is 6, v[1] is 7
slice[0] is 9, copy is 6, v[1] is 7
=============

View File

@@ -0,0 +1,103 @@
// -*- mode:c++; switch-modules-target: "container_proxy.hpp" -*-
//
// Header file shared_proxy_impl.hpp
//
// The shared implementation of the element proxy (const and non-const
// versions). Multiple proxy pointers can refer to the same shared
// implementation, meaning that only one object requires updating to
// affect all proxy pointers that ultimately refer to the same index
// in the container.
//
// Copyright (c) 2003 Raoul M. Gough
//
// This material is provided "as is", with absolutely no warranty expressed
// or implied. Any use is at your own risk.
//
// Permission to use or copy this material for any purpose is hereby
// granted without fee, provided the above notices are retained on all
// copies. Permission to modify the material and to distribute modified
// versions is granted, provided the above notices are retained, and a
// notice that the material was modified is included with the above
// copyright notice.
//
// History
// =======
// 2003/ 8/29 rmg File creation from container_proxy.hh
//
// $Id$
//
#ifndef shared_proxy_impl_rmg_20030829_included
#define shared_proxy_impl_rmg_20030829_included
#include <memory>
template<class ContainerProxy>
class shared_proxy_impl
{
public:
typedef typename ContainerProxy::raw_value_type value_type;
typedef value_type &reference;
typedef value_type *pointer;
typedef void iterator_category; // Fudge for boost::indirect_iterator
typedef void difference_type; // Fudge for boost::indirect_iterator
reference operator*() const;
pointer operator->() const { return &(**this); }
ContainerProxy *owner() const { return myOwnerPtr; }
size_t index() const { return myIndex; }
shared_proxy_impl (value_type const &copy);
// Creates value-only (detached) proxy
private:
template<class C, typename H, class A> friend class container_proxy;
shared_proxy_impl (ContainerProxy *, size_t);
void detach ();
private:
ContainerProxy *myOwnerPtr; // When attached
size_t myIndex; // When attached
std::auto_ptr<value_type> myElementPtr; // When detached
private:
// Not implemented
shared_proxy_impl (shared_proxy_impl const &);
shared_proxy_impl &operator= (shared_proxy_impl const &);
};
template<class ContainerProxy>
shared_proxy_impl<ContainerProxy>::shared_proxy_impl (ContainerProxy *ownerPtr
, size_t index)
: myOwnerPtr (ownerPtr)
, myIndex (index)
, myElementPtr ()
{
}
template<class ContainerProxy>
shared_proxy_impl<ContainerProxy>::shared_proxy_impl (value_type const &val)
: myOwnerPtr (0)
, myIndex (-1)
, myElementPtr (new value_type (val))
{
}
template<class ContainerProxy>
typename shared_proxy_impl<ContainerProxy>::reference
shared_proxy_impl<ContainerProxy>::operator* () const
{
return myOwnerPtr ? myOwnerPtr->container().at (myIndex) : *myElementPtr;
}
template<class ContainerProxy>
void shared_proxy_impl<ContainerProxy>::detach ()
{
myElementPtr.reset (new value_type (**this));
myOwnerPtr = 0;
myIndex = static_cast<size_t>(-1);
}
#endif // shared_proxy_impl_rmg_20030829_included

View File

@@ -0,0 +1,211 @@
// -*- mode:c++ -*-
//
// Header file suite_utils.hpp
//
// Copyright (c) 2003 Raoul M. Gough
//
// This material is provided "as is", with absolutely no warranty expressed
// or implied. Any use is at your own risk.
//
// Permission to use or copy this material for any purpose is hereby
// granted without fee, provided the above notices are retained on all
// copies. Permission to modify the material and to distribute modified
// versions is granted, provided the above notices are retained, and a
// notice that the material was modified is included with the above
// copyright notice.
//
// History
// =======
// 2003/ 8/23 rmg File creation
//
// $Id$
//
#ifndef suite_utils_rmg_20030823_included
#define suite_utils_rmg_20030823_included
#include <boost/type_traits.hpp>
#include <boost/call_traits.hpp>
#include <algorithm>
namespace indexing {
template<typename T>
class is_mutable_ref
{
typedef typename boost::remove_reference<T>::type maybe_const;
public:
static bool const value = ! boost::is_const<maybe_const>::value;
};
template<typename ContainerTraits>
struct container_algorithms
{
typedef typename ContainerTraits::container container;
typedef typename ContainerTraits::iterator iterator;
typedef typename ContainerTraits::key_type key_type;
typedef typename ContainerTraits::size_type size_type;
typedef typename ContainerTraits::index_type index_type;
typedef typename boost::call_traits<key_type>::param_type key_param;
typedef typename boost::call_traits<index_type>::param_type index_param;
static size_type size (container &);
static iterator find (container &, key_param);
static size_type count (container &, key_param);
static void reverse (container &);
static iterator at (container&, index_param);
static void sort (container &);
// static void sort (container &, PyObject *);
};
/////////////////////////////////////////////////////////////////////////
// Get the size of a container
/////////////////////////////////////////////////////////////////////////
template<typename ContainerTraits>
typename container_algorithms<ContainerTraits>::size_type
container_algorithms<ContainerTraits>::size (container &c)
{
return c.size();
}
/////////////////////////////////////////////////////////////////////////
// Find an element in a container (std algorithm version)
/////////////////////////////////////////////////////////////////////////
template<typename ContainerTraits>
typename container_algorithms<ContainerTraits>::iterator
container_algorithms<ContainerTraits>::find (container &c
, key_param key)
{
return std::find (c.begin(), c.end(), key);
}
/////////////////////////////////////////////////////////////////////////
// Count occurances of an element in a container (std algorithm version)
/////////////////////////////////////////////////////////////////////////
template<typename ContainerTraits>
typename container_algorithms<ContainerTraits>::size_type
container_algorithms<ContainerTraits>::count (container &c
, key_param key)
{
return std::count (c.begin(), c.end(), key);
}
/////////////////////////////////////////////////////////////////////////
// Index into a container (iterator version)
/////////////////////////////////////////////////////////////////////////
template<typename ContainerTraits>
typename container_algorithms<ContainerTraits>::iterator
container_algorithms<ContainerTraits>::at (container &c, index_param ix)
{
return c.begin() + ix;
}
/////////////////////////////////////////////////////////////////////////
// Reverse the contents of a container (std algorithm version)
/////////////////////////////////////////////////////////////////////////
template<typename ContainerTraits>
void container_algorithms<ContainerTraits>::reverse (container &c)
{
std::reverse (c.begin(), c.end());
}
/////////////////////////////////////////////////////////////////////////
// Sort the contents of a container (std algorithm version)
/////////////////////////////////////////////////////////////////////////
template<typename ContainerTraits>
void container_algorithms<ContainerTraits>::sort (container &c)
{
std::sort (c.begin(), c.end());
}
/////////////////////////////////////////////////////////////////////////
// Special cases for std::list
/////////////////////////////////////////////////////////////////////////
template<typename ContainerTraits>
struct list_algorithms : public container_algorithms<ContainerTraits>
{
private:
typedef container_algorithms<ContainerTraits> Parent;
public:
typedef typename Parent::container container;
// Use member functions for the following (hiding base class versions)
static void reverse (container &);
static void sort (container &);
// static void sort (container &, PyObject *);
};
/////////////////////////////////////////////////////////////////////////
// Reverse the contents of a list (member function version)
/////////////////////////////////////////////////////////////////////////
template<typename ContainerTraits>
void list_algorithms<ContainerTraits>::reverse (container &c)
{
c.reverse();
}
/////////////////////////////////////////////////////////////////////////
// Sort the contents of a container (std algorithm version)
/////////////////////////////////////////////////////////////////////////
template<typename ContainerTraits>
void list_algorithms<ContainerTraits>::sort (container &c)
{
c.sort();
}
/////////////////////////////////////////////////////////////////////////
// Special cases for associative containers
/////////////////////////////////////////////////////////////////////////
template<typename ContainerTraits>
struct assoc_algorithms : public container_algorithms<ContainerTraits>
{
private:
typedef container_algorithms<ContainerTraits> Parent;
public:
typedef typename Parent::iterator iterator;
typedef typename Parent::size_type size_type;
typedef typename Parent::container container;
typedef typename Parent::key_param key_param;
// Use member functions for the following (hiding base class versions)
static iterator find (container &, key_param);
static size_type count (container &, key_param);
};
/////////////////////////////////////////////////////////////////////////
// Find an element in an associative container
/////////////////////////////////////////////////////////////////////////
template<typename ContainerTraits>
typename assoc_algorithms<ContainerTraits>::iterator
assoc_algorithms<ContainerTraits>::find (container &c, key_param key)
{
return c.find (key);
}
/////////////////////////////////////////////////////////////////////////
// Count occurances of an element in a container (std algorithm version)
/////////////////////////////////////////////////////////////////////////
template<typename ContainerTraits>
typename assoc_algorithms<ContainerTraits>::size_type
assoc_algorithms<ContainerTraits>::count (container &c, key_param key)
{
return c.count (key);
}
}
#endif // suite_utils_rmg_20030823_included

View File

@@ -0,0 +1,145 @@
// -*- mode:c++; switch-modules-target: "container_proxy.hpp" -*-
//
// Module testcontprox.cpp
//
// Copyright (c) 2003 Raoul M. Gough
//
// This material is provided "as is", with absolutely no warranty expressed
// or implied. Any use is at your own risk.
//
// Permission to use or copy this material for any purpose is hereby
// granted without fee, provided the above notices are retained on all
// copies. Permission to modify the material and to distribute modified
// versions is granted, provided the above notices are retained, and a
// notice that the material was modified is included with the above
// copyright notice.
//
// History
// =======
// 2003/ 8/26 rmg File creation
//
// $Id$
//
#include "container_proxy.hpp"
#include <cstdio>
#include <vector>
#include <sstream>
#include <ostream>
#include <iostream>
#include <iterator>
#include <boost/iterator/indirect_iterator.hpp>
int unique_int() {
static int counter = 400;
return counter++;
}
int main ()
{
int i = unique_int();
typedef std::vector<int> Container;
typedef container_proxy<Container, Container *, deref<Container> > ContainerProxy;
Container raw_container;
raw_container.push_back (i);
ContainerProxy proxy (&raw_container);
std::cout
<< proxy.container().front() // Should be first element
<< " "
<< *proxy.at (0) // Should be the same
<< "\n";
ContainerProxy::value_type ptr (proxy.at (0));
std::cout
<< *ptr // Should be first element
<< " "
<< ptr.use_count(); // Should be 2 (internal map has a ref)
{
ContainerProxy::const_value_type
const_ptr (const_cast<ContainerProxy const &>(proxy).at(0));
std::cout
<< ", "
<< *const_ptr // Should also be first element
<< " "
<< ptr.use_count(); // Should be 3 (two proxies and internal)
}
proxy.replace (0, unique_int());
std::cout
<< ", "
<< *ptr // Should be *original* first element
<< " "
<< ptr.use_count() // Should be 1 (detached)
<< ", "
<< proxy.at (0) // Should be new first element
<< "\n";
ptr = proxy.at (0); // Proxy to new first element (attached)
proxy.insert (proxy.begin(), unique_int());
proxy.insert (proxy.begin(), unique_int());
int array[4];
for (int count = 0; count < 4; ++count) array[count] = unique_int();
proxy.insert (proxy.begin(), array, array + 4);
std::cout << "(" << *ptr << ", " << ptr.use_count() << ") ";
std::copy (raw_container.begin(), raw_container.end()
, std::ostream_iterator<int>(std::cout, " "));
std::cout << "\n";
proxy.erase (proxy.begin());
proxy.erase (proxy.begin(), proxy.begin() + 3);
std::cout << "(" << *ptr << ", " << ptr.use_count() << ") ";
std::copy (raw_container.begin(), raw_container.end()
, std::ostream_iterator<int>(std::cout, " "));
std::cout << "\n";
std::stringstream strm;
strm << unique_int();
strm << " " << unique_int();
proxy.insert (proxy.begin()
, std::istream_iterator<int> (strm)
, std::istream_iterator<int> ());
std::cout << "(" << *ptr << ", " << ptr.use_count() << ") ";
std::copy (raw_container.begin(), raw_container.end()
, std::ostream_iterator<int>(std::cout, " "));
std::cout << "\n";
// Example set_item implementation - replacing the slice [1:4] with a
// single element
proxy.detach_proxy (1);
proxy.at(1) = unique_int(); // Replace with new element
proxy.erase (proxy.begin() + 2, proxy.begin() + 4);
std::cout << "(" << *ptr << ", " << ptr.use_count() << ") ";
// Try indirect_iterator just for fun, but this creates proxies for
// every element in the container!
using boost::make_indirect_iterator;
std::copy (make_indirect_iterator(proxy.begin())
, make_indirect_iterator(proxy.end())
, std::ostream_iterator<int>(std::cout, " "));
std::cout << "\n";
// Try erasing the whole container, make sure proxy has value and is unique
proxy.erase (proxy.begin(), proxy.end());
std::cout
<< "(" << *ptr << ", " << ptr.use_count() << ") "
<< proxy.size() << "\n";
}

View File

@@ -0,0 +1,70 @@
#!/usr/bin/python
# -*- mode:python; switch-modules-target: "indexing.cpp" -*-
#
# Python module testindexing.py
#
# Copyright (c) 2003 Raoul M. Gough
#
# This material is provided "as is", with absolutely no warranty expressed
# or implied. Any use is at your own risk.
#
# Permission to use or copy this software for any non-commercial purpose
# is hereby granted without fee, provided the above notices are retained
# on all copies. Permission to modify the code and to distribute
# modified code for non-commercial purposes is granted, provided the
# above notices are retained, and a notice that the code was modified is
# included with the above copyright notice.
#
# History
# =======
# 2003/ 8/19 rmg File creation
#
# $Id$
#
from indexing import *
trace(0)
def test_from_empty(v):
# v.reserve (10);
print v
v.append (IntWrapper (1))
v.append (IntWrapper (2))
v.append (IntWrapper (3))
print v[0], v[1], v[2]
try:
print v[0], v[1:][0], v[-1:][0]
except Exception, e:
print e
pass
copy = v[1]
print "copy is %s, v[1] is %s" % (copy, v[1])
v[1].increment()
print "copy is %s, v[1] is %s" % (copy, v[1])
v[1] = IntWrapper (5)
print "copy is %s, v[1] is %s" % (copy, v[1])
slice = v[1:2]
copy = slice[0]
print "slice[0] is %s, copy is %s, v[1] is %s" % (slice[0], copy, v[1])
v[1].increment()
print "slice[0] is %s, copy is %s, v[1] is %s" % (slice[0], copy, v[1])
v[1] = IntWrapper (7)
print "slice[0] is %s, copy is %s, v[1] is %s" % (slice[0], copy, v[1])
slice[0] = IntWrapper (9)
print "slice[0] is %s, copy is %s, v[1] is %s" % (slice[0], copy, v[1])
print "============="
test_from_empty (Vector())
test_from_empty (ProxyVector())
test_from_empty (PointerVector())
test_from_empty ([])

View File

@@ -0,0 +1,158 @@
#!/usr/bin/python
# -*- mode:python -*-
#
# Python module testlist.py
#
# Copyright (c) 2003 Raoul M. Gough
#
# This material is provided "as is", with absolutely no warranty expressed
# or implied. Any use is at your own risk.
#
# Permission to use or copy this material for any purpose is hereby
# granted without fee, provided the above notices are retained on all
# copies. Permission to modify the material and to distribute modified
# versions is granted, provided the above notices are retained, and a
# notice that the material was modified is included with the above
# copyright notice.
#
# History
# =======
# 2003/ 8/20 rmg File creation
#
# $Id$
#
from types import SliceType
class ListIter:
def __init__(self, l):
self.myList = l
self.myIndex = 0
def next(self):
print "next(ListIter)",
try:
result = self.myList[self.myIndex]
self.myIndex += 1
print "ok"
return result
except IndexError:
print "StopIteration"
raise StopIteration
class MyList:
def __init__(self, l = None):
print "__init__(MyList)"
if l == None:
self.myList = list()
else:
self.myList = l
def __setitem__(self, key, value):
print "__setitem__(MyList, %s, %s)" % (key, value)
if isinstance (key, SliceType):
if key.step != None:
raise TypeError ("Invalid slice for list")
self.myList.__setslice__ (key.start, key.stop, value)
else:
self.myList.__setitem__(key, value)
def __iter__(self):
print "__iter__(MyList)"
return ListIter(self.myList)
def __getitem__(self, key):
print "__getitem__(MyList, %s)" % key
if isinstance (key, SliceType):
if key.step != None:
raise TypeError ("Invalid slice for list")
return self.myList.__getslice__ (key.start, key.stop)
return self.myList.__getitem__(key)
def __delitem__(self, key):
print "__delitem__(MyList, %s)" % key
if isinstance (key, SliceType):
if key.step != None:
raise TypeError ("Invalid slice for list")
self.myList.__delslice__ (key.start, key.stop)
else:
self.myList.__delitem__(key)
def __len__(self):
print "__len__(MyList)"
return self.myList.__len__()
def __add__(self, value):
print "__add__(MyList, %s)" % value
return MyList(self.myList.__add__(value))
def __mul__(self, value):
print "__mul__(MyList, %s)" % value
return MyList(self.myList.__mul__(value))
# def __imul__(self, value):
# print "__imul__(MyList, %s)" % value
# self.myList.__imul__(value)
# def __contains__(self, value):
# print "__contains__(MyList, %s)" % value
# return self.myList.__contains__(value)
def append(self, value):
print "append(MyList, %s)" % value
self.myList.append(value)
def __insert__(self, key, value):
print "__insert__(MyList, %s, %s)" % (key, value)
self.myList.__insert__(key, value)
# def __setslice__(self, start, end, value):
# print "__setslice__(MyList, %s, %s, %s)" % (start, end, value)
# self.myList.__setslice__(start, end, value)
# def __getslice__(self, start, end):
# print "__getslice__(MyList, %s, %s)" % (start, end)
# self.myList.__getslice__(start, end)
# def __delslice__(self, start, end):
# print "__delslice__(MyList, %s, %s)" % (start, end)
# self.myList.__delslice__(start, end)
def __repr__(self):
return self.myList.__repr__()
x = MyList()
x.append(4)
x.append(5)
x.append(6)
print 4 in x
print 7 in x
x[1] = 0
x[2:3]=[7, 8, 9]
print x + [10]
print x[2:]
del x[2:3]
del x[0]
print x
x[1:2] = []
print x
x *= 2
print x
x[0:3][0:1] = [1]
print x

View File

@@ -0,0 +1,344 @@
'''
#####################################################################
# 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'
#####################################################################
# Iteration
#####################################################################
>>> 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(sl)
[ yaba c ]
>>> 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
#####################################################################
# Contains
#####################################################################
>>> v[:] = ['a','b','c','d','e'] # reset again
>>> assert 'a' in v
>>> assert 'b' in v
>>> assert 'c' in v
>>> assert 'd' in v
>>> assert 'e' in v
>>> assert not 'X' in v
>>> assert not 12345 in v
#####################################################################
# Show that iteration allows mutable access to the elements
#####################################################################
>>> v[:] = ['a','b','c','d','e'] # reset again
>>> for x in v:
... x.reset()
>>> print_xvec(v)
[ reset reset reset reset reset ]
#####################################################################
# append
#####################################################################
>>> v[:] = ['a','b','c','d','e'] # reset again
>>> v.append('f')
>>> print_xvec(v)
[ a b c d e f ]
#####################################################################
# extend
#####################################################################
>>> v[:] = ['a','b','c','d','e'] # reset again
>>> v.extend(['f','g','h','i','j'])
>>> print_xvec(v)
[ a b c d e f g h i j ]
#####################################################################
# 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])

View File

@@ -0,0 +1,61 @@
#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
#include <boost/python/module.hpp>
#include <boost/python/def.hpp>
#include <boost/python/implicit.hpp>
#include "container_proxy.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"; }
bool operator==(X const& x) const { return s == x.s; }
bool operator!=(X const& x) const { return s != x.s; }
};
std::string x_value(X const& x)
{
return "gotya " + x.s;
}
X *get_pointer (container_proxy<std::vector<X> >::value_type const &proxy)
{
return &(*proxy);
}
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>();
typedef std::vector<X> RawContainer;
typedef container_proxy<RawContainer> Container;
boost::python::register_ptr_to_python<Container::value_type>();
implicitly_convertible<X, Container::value_type>();
class_<Container>("XVec")
.def(vector_indexing_suite<Container, true>())
;
// Compile check only...
class_<std::vector<float> >("FloatVec")
.def(vector_indexing_suite<std::vector<float> >())
;
}

View File

@@ -0,0 +1,33 @@
Index: vector_indexing_suite.hpp
===================================================================
RCS file: /cvsroot/boost/boost/boost/python/suite/indexing/vector_indexing_suite.hpp,v
retrieving revision 1.4
diff -w -d -u -r1.4 vector_indexing_suite.hpp
--- vector_indexing_suite.hpp 14 Aug 2003 12:14:25 -0000 1.4
+++ vector_indexing_suite.hpp 30 Aug 2003 11:47:22 -0000
@@ -52,6 +52,7 @@
public:
typedef typename Container::value_type data_type;
+ typedef typename Container::reference reference_type;
typedef typename Container::value_type key_type;
typedef typename Container::size_type index_type;
typedef typename Container::size_type size_type;
@@ -67,7 +68,7 @@
;
}
- static data_type&
+ static reference_type
get_item(Container& container, index_type i)
{
return container[i];
@@ -185,7 +186,7 @@
static void
base_append(Container& container, PyObject* v)
{
- extract<data_type&> elem(v);
+ extract<reference_type> elem(v);
// try if elem is an exact Data
if (elem.check())
{