From 8311bfa7d929a74edd0922f847b168ca6d06bbe9 Mon Sep 17 00:00:00 2001 From: Raoul Gough Date: Wed, 3 Sep 2003 22:46:14 +0000 Subject: [PATCH 01/39] Added the necessary copy constructor, assignment operator and destructor [SVN r1475] --- .../python/suite/indexing/container_proxy.hpp | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/include/boost/python/suite/indexing/container_proxy.hpp b/include/boost/python/suite/indexing/container_proxy.hpp index 26b39e30..55394428 100755 --- a/include/boost/python/suite/indexing/container_proxy.hpp +++ b/include/boost/python/suite/indexing/container_proxy.hpp @@ -34,11 +34,13 @@ template struct identity { static T & get(T & obj) { return obj; } static T const & get(T const & obj) { return obj; } + // FIXME: should add copy, assign and destroy static members }; template struct deref { template static T & get (U & ptr) { return *ptr; } template static T const & get (U const & ptr) { return *ptr; } + // FIXME: should add copy, assign and destroy static members }; template container_proxy (Iter, Iter); + container_proxy (container_proxy const &); + container_proxy &operator= (container_proxy const &); + ~container_proxy (); + Container & container(); // Should be private? Container const &container() const; // Should be private? @@ -328,6 +334,33 @@ container_proxy insert (begin(), start, finish); } +template +container_proxy +::container_proxy (container_proxy const ©) + : myHeldType (copy.myHeldType) + , myMap () // Do *not* duplicate map +{ +} + +template +container_proxy & +container_proxy +::operator= (container_proxy const ©) +{ + // All of our contained values are about to be dis-owned + std::for_each (myMap.begin(), myMap.end(), detach_if_shared); + myMap.clear(); + myHeldType = copy.myHeldType; +} + +template +container_proxy +::~container_proxy () +{ + // All of our contained values are about to be dis-owned + std::for_each (myMap.begin(), myMap.end(), detach_if_shared); +} + template Container & container_proxy From eec4ec6701092b33cdfc26e41a7be32d691bfb90 Mon Sep 17 00:00:00 2001 From: Raoul Gough Date: Tue, 9 Sep 2003 18:22:32 +0000 Subject: [PATCH 02/39] Renamed at() to get(), some fixes for map type, added assign() [SVN r1508] --- .../python/suite/indexing/suite_utils.hpp | 96 +++++++++++++++++-- 1 file changed, 86 insertions(+), 10 deletions(-) diff --git a/include/boost/python/suite/indexing/suite_utils.hpp b/include/boost/python/suite/indexing/suite_utils.hpp index c9e21afc..4b05b9da 100755 --- a/include/boost/python/suite/indexing/suite_utils.hpp +++ b/include/boost/python/suite/indexing/suite_utils.hpp @@ -27,6 +27,8 @@ #include #include #include +#include +#include namespace indexing { template @@ -43,10 +45,13 @@ namespace indexing { { typedef typename ContainerTraits::container container; typedef typename ContainerTraits::iterator iterator; + typedef typename ContainerTraits::reference reference; typedef typename ContainerTraits::key_type key_type; typedef typename ContainerTraits::size_type size_type; typedef typename ContainerTraits::index_type index_type; + typedef typename ContainerTraits::value_type value_type; + typedef typename boost::call_traits::param_type value_param; typedef typename boost::call_traits::param_type key_param; typedef typename boost::call_traits::param_type index_param; @@ -54,9 +59,14 @@ namespace indexing { static iterator find (container &, key_param); static size_type count (container &, key_param); static void reverse (container &); - static iterator at (container&, index_param); + static reference get (container &, index_param); + static void assign (container &, index_param, value_param); + static void push_back (container &, value_param); static void sort (container &); // static void sort (container &, PyObject *); + + static iterator begin (container &c) { return c.begin(); } + static iterator end (container &c) { return c.end(); } }; ///////////////////////////////////////////////////////////////////////// @@ -79,7 +89,7 @@ namespace indexing { container_algorithms::find (container &c , key_param key) { - return std::find (c.begin(), c.end(), key); + return std::find (begin(c), end(c), key); } ///////////////////////////////////////////////////////////////////////// @@ -91,18 +101,43 @@ namespace indexing { container_algorithms::count (container &c , key_param key) { - return std::count (c.begin(), c.end(), key); + return std::count (begin(c), end(c), key); } ///////////////////////////////////////////////////////////////////////// - // Index into a container (iterator version) + // Index into a container (generic version) ///////////////////////////////////////////////////////////////////////// template - typename container_algorithms::iterator - container_algorithms::at (container &c, index_param ix) + typename container_algorithms::reference + container_algorithms::get (container &c, index_param ix) { - return c.begin() + ix; + return c.at (ix); + } + + ///////////////////////////////////////////////////////////////////////// + // Assign a value at a particular index (generic version) + ///////////////////////////////////////////////////////////////////////// + + template + void + container_algorithms::assign (container &c + , index_param ix + , value_param val) + { + c.at(ix) = val; + } + + ///////////////////////////////////////////////////////////////////////// + // Insert at end of a container (generic version) + ///////////////////////////////////////////////////////////////////////// + + template + void + container_algorithms::push_back (container &c + , value_param v) + { + c.push_back (v); } ///////////////////////////////////////////////////////////////////////// @@ -112,7 +147,7 @@ namespace indexing { template void container_algorithms::reverse (container &c) { - std::reverse (c.begin(), c.end()); + std::reverse (begin(c), end(c)); } ///////////////////////////////////////////////////////////////////////// @@ -122,7 +157,7 @@ namespace indexing { template void container_algorithms::sort (container &c) { - std::sort (c.begin(), c.end()); + std::sort (begin(c), end(c)); } ///////////////////////////////////////////////////////////////////////// @@ -178,13 +213,54 @@ namespace indexing { typedef typename Parent::iterator iterator; typedef typename Parent::size_type size_type; typedef typename Parent::container container; + typedef typename Parent::reference reference; typedef typename Parent::key_param key_param; + typedef typename Parent::index_param index_param; + typedef typename Parent::value_param value_param; + + static reference get (container &, index_param); + static void assign (container &, index_param, value_param); // Use member functions for the following (hiding base class versions) static iterator find (container &, key_param); static size_type count (container &, key_param); }; + ///////////////////////////////////////////////////////////////////////// + // Index into a container (associative version) + ///////////////////////////////////////////////////////////////////////// + + template + typename assoc_algorithms::reference + assoc_algorithms::get (container &c, index_param ix) + { + iterator iter = find (c, ix); + + if (iter == end(c)) + { + throw std::domain_error + (std::string ("associative container: key not found")); + } + + else + { + return iter->second; + } + } + + ///////////////////////////////////////////////////////////////////////// + // Assign a value at a particular index (associative version) + ///////////////////////////////////////////////////////////////////////// + + template + void + assoc_algorithms::assign (container &c + , index_param ix + , value_param val) + { + c[ix] = val; + } + ///////////////////////////////////////////////////////////////////////// // Find an element in an associative container ///////////////////////////////////////////////////////////////////////// @@ -197,7 +273,7 @@ namespace indexing { } ///////////////////////////////////////////////////////////////////////// - // Count occurances of an element in a container (std algorithm version) + // Count occurances of an element in a container (associative version) ///////////////////////////////////////////////////////////////////////// template From 74e16eb65129a7b667880bc9acbea1a8af166ce1 Mon Sep 17 00:00:00 2001 From: Raoul Gough Date: Tue, 9 Sep 2003 18:23:45 +0000 Subject: [PATCH 03/39] Extract traits into separate header, started implementation of suite [SVN r1509] --- .../python/suite/indexing/container_suite.hpp | 410 +++++------------- 1 file changed, 112 insertions(+), 298 deletions(-) diff --git a/include/boost/python/suite/indexing/container_suite.hpp b/include/boost/python/suite/indexing/container_suite.hpp index 3112e947..640736c1 100755 --- a/include/boost/python/suite/indexing/container_suite.hpp +++ b/include/boost/python/suite/indexing/container_suite.hpp @@ -17,6 +17,7 @@ // History // ======= // 2003/ 8/23 rmg File creation +// 2003/ 9/ 8 rmg Extracted trait facilities into container_traits.hpp // // $Id$ // @@ -24,325 +25,138 @@ #ifndef container_suite_rmg_20030823_included #define container_suite_rmg_20030823_included -#include "suite_utils.hpp" -#include "iterator_suite.hpp" -#include +#include "container_traits.hpp" +#include "slice_handler.hpp" -#include -#include -#include -#include -#include +#include +#include +#include +#include + +// #include namespace indexing { - ////////////////////////////////////////////////////////////////////////// - // Iterator pair container emulation - ////////////////////////////////////////////////////////////////////////// - - template - class iterator_pair - { - private: - typedef typename boost::call_traits::param_type iterator_param; - typedef std::iterator_traits 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 + struct maybe_add_getitem { + template + static void apply (PythonClass &, Algorithms const &, Policy const &) { } }; - template - iterator_pair::iterator_pair (iterator_param begin - , iterator_param end) - : myBegin (begin) - , myEnd (end) - { - } - - template - typename iterator_pair::iterator - iterator_pair::begin() const - { - return myBegin; - } - - template - typename iterator_pair::iterator - iterator_pair::end() const - { - return myEnd; - } - - template - typename iterator_pair::size_type - iterator_pair::size() const - { - return std::distance (begin(), end()); - } - - template - typename iterator_pair::reference - iterator_pair::operator[](size_type index) const - { - return *(begin() + index); - } - - ///////////////////////////////////////////////////////////////////////// - // Container traits - ///////////////////////////////////////////////////////////////////////// - - ///////////////////////////////////////////////////////////////////////// - // Traits for the iterator_pair container emulator - ///////////////////////////////////////////////////////////////////////// - - template - struct iterator_pair_traits - : public - iterator_detail::traits_by_category::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 algorithms; + template<> + struct maybe_add_getitem { + template + static void apply (PythonClass &pyClass + , Algorithms const & + , Policy const &policy) + { + pyClass.def ("__getitem__", &Algorithms::get, policy); + } }; - ///////////////////////////////////////////////////////////////////////// - // Lowest common denominator (almost all "real" containers would - // meet at least these requirements) - ///////////////////////////////////////////////////////////////////////// - - template - struct default_container_traits - { - protected: - static bool const is_mutable = ! boost::is_const::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::has_random_access; - - static bool const has_mutable_ref - = is_mutable && is_mutable_ref::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 algorithms; + template<> + struct maybe_add_getitem { + template + static void apply (PythonClass &pyClass + , Algorithms const & + , Policy const &policy) + { + pyClass.def ("__getitem__" + , slice_handler::make_getitem (policy)); + } }; - ///////////////////////////////////////////////////////////////////////// - // Sequences (list, deque, vector) - ///////////////////////////////////////////////////////////////////////// - - template - struct default_sequence_traits : public default_container_traits - { - static bool const has_pop_back = is_mutable; - static bool const has_push_back = is_mutable; + template + struct maybe_add_setitem { + template + static void apply (PythonClass &, Algorithms const &, Policy const &) { } }; - template - struct list_traits : public default_sequence_traits - { - // Some special algo's for list (using member functions) - typedef list_algorithms algorithms; + template<> + struct maybe_add_setitem { + template + static void apply (PythonClass &pyClass + , Algorithms const & + , Policy const &policy) + { + pyClass.def ("__setitem__", &Algorithms::assign, policy); + } }; - ///////////////////////////////////////////////////////////////////////// - // Associative containers set and multiset - ///////////////////////////////////////////////////////////////////////// - - template - struct set_traits : public default_container_traits - { - // Special algo's for set types (using member functions) - typedef assoc_algorithms algorithms; + template<> + struct maybe_add_setitem { + template + static void apply (PythonClass &pyClass + , Algorithms const & + , Policy const &policy) + { + pyClass.def ("__setitem__", &Algorithms::assign, policy); + // *FIXME* add slicing support + } }; - ///////////////////////////////////////////////////////////////////////// - // Associative containers map and multimap - ///////////////////////////////////////////////////////////////////////// - - template - struct map_traits : public default_container_traits - { - typedef typename Container::key_type key_type; // find, count, ... - - // Special algo's for map types (using member functions) - typedef assoc_algorithms algorithms; + template + struct maybe_add_iter { + template + static void apply (PythonClass &, Algorithms const &, Policy const &) { } }; - ///////////////////////////////////////////////////////////////////////// - // Automated trait selection - ///////////////////////////////////////////////////////////////////////// - - namespace container_details { - template 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 traits_by_type > + template<> + struct maybe_add_iter { + template + static void apply (PythonClass &pyClass + , Algorithms const & + , Policy const &policy) { - typedef std::set Container; - - public: - typedef set_traits mutable_type; - typedef set_traits const_type; - }; - - // std::multiset - template - class traits_by_type > - { - typedef std::multiset Container; - - public: - typedef set_traits mutable_type; - typedef set_traits const_type; - }; - - // std::map - template - class traits_by_type > - { - typedef std::map Container; - - public: - typedef map_traits mutable_type; - typedef map_traits const_type; - }; - - // std::multimap - template - class traits_by_type > - { - typedef std::multimap Container; - - public: - typedef map_traits mutable_type; - typedef map_traits const_type; - }; - - // std::vector - template - class traits_by_type > - { - typedef std::vector Container; - - public: - typedef default_sequence_traits mutable_type; - typedef default_sequence_traits const_type; - }; - - // std::deque - template - class traits_by_type > - { - typedef std::deque Container; - - public: - typedef default_sequence_traits mutable_type; - typedef default_sequence_traits const_type; - }; - - // std::list - template - class traits_by_type > - { - typedef std::list Container; - - public: - typedef list_traits mutable_type; - typedef list_traits const_type; - }; - - // Iterator ranges - template - class traits_by_type > - { - typedef ::indexing::iterator_pair Container; - - public: - typedef iterator_pair_traits mutable_type; - typedef iterator_pair_traits const_type; // ? - }; - } - - // Select the right traits for each supported kind of container - - // Generic version (mutable containers) - template - struct container_traits - : public container_details::traits_by_type::mutable_type - { + pyClass.def ("__iter__" + , boost::python::range (Algorithms::begin + , Algorithms::end)); + } }; - // Partial specialization for const containers - template - struct container_traits - : public container_details::traits_by_type::const_type + template + struct maybe_add_append { + template + static void apply (PythonClass &, Algorithms const &, Policy const &) { } + }; + + template<> + struct maybe_add_append { + template + static void apply (PythonClass &pyClass + , Algorithms const & + , Policy const &policy) + { + pyClass.def ("append", &Algorithms::push_back, policy); + } + }; + + template > + struct container_suite + : public boost::python::def_visitor > { + typedef typename Traits::algorithms algorithms; + typedef typename Traits::reference reference_return; + + typedef boost::python::return_value_policy + return_policy; + + template + static void visit (PythonClass &pyClass) + { + maybe_add_getitem + ::apply (pyClass, algorithms(), return_policy()); + + maybe_add_setitem + ::apply (pyClass, algorithms(), return_policy()); + + maybe_add_iter<((Traits::index_style != index_style_linear) + && Traits::has_copyable_iter)> + ::apply (pyClass, algorithms(), return_policy()); + + maybe_add_append + ::apply (pyClass, algorithms(), return_policy()); + } }; } From 38c3f0867d9156c59430b2eca1c789d4d3b994a8 Mon Sep 17 00:00:00 2001 From: Raoul Gough Date: Tue, 9 Sep 2003 18:24:16 +0000 Subject: [PATCH 04/39] Container traits for the indexing suite [SVN r1510] --- .../suite/indexing/container_traits.hpp | 281 ++++++++++++++++++ 1 file changed, 281 insertions(+) create mode 100755 include/boost/python/suite/indexing/container_traits.hpp diff --git a/include/boost/python/suite/indexing/container_traits.hpp b/include/boost/python/suite/indexing/container_traits.hpp new file mode 100755 index 00000000..04b4abff --- /dev/null +++ b/include/boost/python/suite/indexing/container_traits.hpp @@ -0,0 +1,281 @@ +// -*- mode:c++ -*- +// +// Header file container_traits.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 as container_suite.hpp +// 2003/ 9/ 8 rmg Renamed container_traits.hpp +// +// $Id$ +// + +#ifndef container_traits_rmg_20030823_included +#define container_traits_rmg_20030823_included + +#include "suite_utils.hpp" +#include "iterator_suite.hpp" +#include + +#include "iterator_pair.hpp" +#include +#include +#include +#include +#include + +namespace indexing { + ///////////////////////////////////////////////////////////////////////// + // Traits for the iterator_pair container emulator + ///////////////////////////////////////////////////////////////////////// + + template + struct iterator_pair_traits + : public + iterator_detail::traits_by_category::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 algorithms; + }; + + ///////////////////////////////////////////////////////////////////////// + // Lowest common denominator (almost all "real" containers would + // meet at least these requirements) + ///////////////////////////////////////////////////////////////////////// + + template + struct default_container_traits + { + protected: + static bool const is_mutable = ! boost::is_const::value; + + public: + typedef Container container; + + // *FIXME* should use value_type const and const_reference if !is_mutable + 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 IndexStyle const index_style + = ::indexing::iterator_traits::index_style; + + static bool const has_mutable_ref + = is_mutable && is_mutable_ref::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 algorithms; + }; + + ///////////////////////////////////////////////////////////////////////// + // Sequences (list, deque, vector) + ///////////////////////////////////////////////////////////////////////// + + template + struct default_sequence_traits : public default_container_traits + { + static bool const has_pop_back = is_mutable; + static bool const has_push_back = is_mutable; + }; + + template + struct list_traits : public default_sequence_traits + { + // Some special algo's for list (using member functions) + typedef list_algorithms algorithms; + }; + + ///////////////////////////////////////////////////////////////////////// + // Associative containers set and multiset + ///////////////////////////////////////////////////////////////////////// + + template + struct set_traits : public default_container_traits + { + static IndexStyle const index_style = index_style_nonlinear; + + // Special algo's for set types (using member functions) + typedef assoc_algorithms algorithms; + }; + + ///////////////////////////////////////////////////////////////////////// + // Associative containers map and multimap + ///////////////////////////////////////////////////////////////////////// + + template + struct map_traits : public default_container_traits + { + // *FIXME* handle const maps + typedef typename Container::mapped_type value_type; + typedef value_type & reference; + typedef typename Container::key_type index_type; // at() + typedef typename Container::key_type key_type; // find, count, ... + + static IndexStyle const index_style = index_style_nonlinear; + + // Special algo's for map types (using member functions) + typedef assoc_algorithms algorithms; + }; + + ///////////////////////////////////////////////////////////////////////// + // Automated trait selection + ///////////////////////////////////////////////////////////////////////// + + namespace container_details { + template 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 traits_by_type > + { + typedef std::set Container; + + public: + typedef set_traits mutable_type; + typedef set_traits const_type; + }; + + // std::multiset + template + class traits_by_type > + { + typedef std::multiset Container; + + public: + typedef set_traits mutable_type; + typedef set_traits const_type; + }; + + // std::map + template + class traits_by_type > + { + typedef std::map Container; + + public: + typedef map_traits mutable_type; + typedef map_traits const_type; + }; + + // std::multimap + template + class traits_by_type > + { + typedef std::multimap Container; + + public: + typedef map_traits mutable_type; + typedef map_traits const_type; + }; + + // std::vector + template + class traits_by_type > + { + typedef std::vector Container; + + public: + typedef default_sequence_traits mutable_type; + typedef default_sequence_traits const_type; + }; + + // std::deque + template + class traits_by_type > + { + typedef std::deque Container; + + public: + typedef default_sequence_traits mutable_type; + typedef default_sequence_traits const_type; + }; + + // std::list + template + class traits_by_type > + { + typedef std::list Container; + + public: + typedef list_traits mutable_type; + typedef list_traits const_type; + }; + + // Iterator ranges + template + class traits_by_type > + { + typedef ::indexing::iterator_pair Container; + + public: + typedef iterator_pair_traits mutable_type; + typedef iterator_pair_traits const_type; // ? + }; + } + + // Select the right traits for each supported kind of container + + // Generic version (mutable containers) + template + struct container_traits + : public container_details::traits_by_type::mutable_type + { + }; + + // Partial specialization for const containers + template + struct container_traits + : public container_details::traits_by_type::const_type + { + }; +} + +#endif // container_suite_rmg_20030823_included From 832e0ef2c586a4b53599ba4b224abac241b4d3ee Mon Sep 17 00:00:00 2001 From: Raoul Gough Date: Tue, 9 Sep 2003 18:24:50 +0000 Subject: [PATCH 05/39] Container emulation using a pair of iterators [SVN r1511] --- .../python/suite/indexing/iterator_pair.hpp | 137 ++++++++++++++++++ 1 file changed, 137 insertions(+) create mode 100755 include/boost/python/suite/indexing/iterator_pair.hpp diff --git a/include/boost/python/suite/indexing/iterator_pair.hpp b/include/boost/python/suite/indexing/iterator_pair.hpp new file mode 100755 index 00000000..e86e427b --- /dev/null +++ b/include/boost/python/suite/indexing/iterator_pair.hpp @@ -0,0 +1,137 @@ +// -*- mode:c++ -*- +// +// Header file iterator_pair.hpp +// +// Emulate an STL container using a pair of iterators. Doesn't support +// insertion or deletion, for the obvious reasons. +// +// 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/ 9/ 9 rmg File creation +// +// $Id$ +// + +#ifndef iterator_pair_rmg_20030909_included +#define iterator_pair_rmg_20030909_included + +#include +#include +#include + +namespace indexing { + template + class iterator_pair + { + private: + typedef typename boost::call_traits::param_type iterator_param; + typedef std::iterator_traits 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; + reference at (size_type) const; + + private: + iterator myBegin; + iterator myEnd; + }; + + template + iterator_pair::iterator_pair (iterator_param begin + , iterator_param end) + : myBegin (begin) + , myEnd (end) + { + } + + template + typename iterator_pair::iterator + iterator_pair::begin() const + { + return myBegin; + } + + template + typename iterator_pair::iterator + iterator_pair::end() const + { + return myEnd; + } + + template + typename iterator_pair::size_type + iterator_pair::size() const + { + return std::distance (begin(), end()); + } + + template + typename iterator_pair::reference + iterator_pair::operator[](size_type index) const + { + iterator temp (begin()); + std::advance (temp, index); + return *temp; + } + + template + typename iterator_pair::reference + iterator_pair::at (size_type index) const + { + if (index >= size()) + { + throw std::out_of_range + (std::string ("iterator_pair: index out of range")); + } + + else + { + return (*this)[index]; + } + } + + template + T *begin (T(&array)[N]) { + return array; + } + + template + T *end (T(&array)[N]) { + return array + N; + } +} + +#endif // iterator_pair_rmg_20030909_included From 12b4c3efc926d090badf3957061adffc12018ee0 Mon Sep 17 00:00:00 2001 From: Raoul Gough Date: Tue, 9 Sep 2003 18:25:27 +0000 Subject: [PATCH 06/39] Slice support functions [SVN r1512] --- .../python/suite/indexing/slice_handler.hpp | 97 +++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100755 include/boost/python/suite/indexing/slice_handler.hpp diff --git a/include/boost/python/suite/indexing/slice_handler.hpp b/include/boost/python/suite/indexing/slice_handler.hpp new file mode 100755 index 00000000..357b9ec8 --- /dev/null +++ b/include/boost/python/suite/indexing/slice_handler.hpp @@ -0,0 +1,97 @@ +// -*- mode:c++ -*- +// +// Header file slice_handler.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/ 9/ 9 rmg File creation +// +// $Id$ +// + +#ifndef slice_handler_rmg_20030909_included +#define slice_handler_rmg_20030909_included + +#include +#include + +// #include + +namespace indexing +{ + struct slice + { + long start; + long step; // Extended slices (currently unsupported) + long stop; + + // Implement from_python using: + // + // PySlice_GetIndices + // (PySliceObject *slice, int length, int *start, int *stop, int *step) + }; + + template + struct slice_handler + { + typedef typename Algorithms::container container; + typedef typename Algorithms::index_param index_param; + typedef typename Algorithms::value_type value_type; + typedef typename Algorithms::reference reference; + + static PyObject *get_slice (container &c, slice const &sl) + { + boost::python::list temp; + + for (long index = sl.start; index < sl.stop; index += sl.step) + { + // *FIXME* handle return policies for each element? + temp.append (Algorithms::get (c, index)); + } + + PyObject *result = list.ptr(); + Py_INCREF (result); + return result; + } + + static reference get_plain (container &c, index_param ix) + { + return Algorithms::get (c, ix); + } + + static PyObject *get_automatic (PyObject *args + , PyObject *keywords + , boost::python::object plain_function + , boost::python::object slice_function) + { + // ? + return 0; + } + + static boost::python::object make_getitem (Policy const &policy) + { + // ? Is there an easy way to generate a function that will + // call get_plain or get_slice depending on the arguments? + // + // Could be done by using get_automatic as a dispatcher, with + // the last two parameters bound to wrappers for the two + // implementations, but maybe there is a better way. + + return boost::python::make_function (get_plain, policy); + } + }; +} + +#endif // slice_handler_rmg_20030909_included From eac3f3d9ad26d7d667cead61befad37233d879d3 Mon Sep 17 00:00:00 2001 From: Raoul Gough Date: Tue, 9 Sep 2003 18:26:11 +0000 Subject: [PATCH 07/39] Python extension module with various indexing suite instantiations for testing [SVN r1513] --- .../boost/python/suite/indexing/testsuite.cpp | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100755 include/boost/python/suite/indexing/testsuite.cpp diff --git a/include/boost/python/suite/indexing/testsuite.cpp b/include/boost/python/suite/indexing/testsuite.cpp new file mode 100755 index 00000000..426b3e0d --- /dev/null +++ b/include/boost/python/suite/indexing/testsuite.cpp @@ -0,0 +1,67 @@ +// -*- mode:c++ -*- +// +// Module testsuite.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/ 9/ 8 rmg File creation +// +// $Id$ +// + +#include "container_suite.hpp" + +#include +#include +#include +#include +#include +#include + +#include "iterator_pair.hpp" + +indexing::iterator_pair getArray() +{ + static int array[] = { 8, 7, 6, 5, 4, 3, 2, 1, 0 }; + + return indexing::iterator_pair(indexing::begin(array) + , indexing::end(array)); +} + +BOOST_PYTHON_MODULE(testsuite) +{ + typedef std::vector Container1; + + boost::python::class_("Vector") + .def (indexing::container_suite()); + + typedef std::list Container2; + + boost::python::class_("List") + .def (indexing::container_suite()); + + typedef std::map Container3; + + boost::python::class_("Map") + .def (indexing::container_suite()); + + typedef indexing::iterator_pair Container4; + + boost::python::class_("Array" + , boost::python::init()) + .def (indexing::container_suite()); + + boost::python::def ("getArray", getArray); +} From 081251bc8aa7aed5aabe2f491d3f510ab98acb04 Mon Sep 17 00:00:00 2001 From: Raoul Gough Date: Tue, 9 Sep 2003 18:27:28 +0000 Subject: [PATCH 08/39] Use an enumerated type for indexing styles [SVN r1514] --- .../python/suite/indexing/iterator_suite.hpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/include/boost/python/suite/indexing/iterator_suite.hpp b/include/boost/python/suite/indexing/iterator_suite.hpp index 146e3669..ed6bffbb 100755 --- a/include/boost/python/suite/indexing/iterator_suite.hpp +++ b/include/boost/python/suite/indexing/iterator_suite.hpp @@ -31,6 +31,12 @@ #include namespace indexing { + enum IndexStyle { + index_style_none // No random access (iteration only) + , index_style_nonlinear // Random access by key (no slicing) + , index_style_linear // Random access by integer index (allows slicing) + }; + ////////////////////////////////////////////////////////////////////////// // Indexing traits for containers based on iterator pairs ////////////////////////////////////////////////////////////////////////// @@ -49,10 +55,10 @@ namespace indexing { 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::value; + static bool const has_copyable_iter = false; + static bool const is_reversible = false; + static bool const has_mutable_ref = is_mutable_ref::value; + static IndexStyle const index_style = index_style_none; }; template @@ -73,7 +79,7 @@ namespace indexing { struct random_access_iterator_traits : public bidirectional_iterator_traits { - static bool const has_random_access = true; + static IndexStyle const index_style = index_style_linear; }; namespace iterator_detail { From ea7015fae1bc8f1c70dafe13118ce518aaed325c Mon Sep 17 00:00:00 2001 From: Raoul Gough Date: Tue, 9 Sep 2003 18:28:14 +0000 Subject: [PATCH 09/39] Include new files to date [SVN r1515] --- include/boost/python/suite/indexing/CONTENTS | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/include/boost/python/suite/indexing/CONTENTS b/include/boost/python/suite/indexing/CONTENTS index 58cf66bb..bb9756db 100755 --- a/include/boost/python/suite/indexing/CONTENTS +++ b/include/boost/python/suite/indexing/CONTENTS @@ -1,4 +1,13 @@ +container_suite.hpp Top-level do-all suite for all supported container types +container_traits.hpp Container traits +iterator_suite.hpp (misnamed) Iterator traits +suite_utils.hpp Utilities to abstract away container interface diffs +iterator_pair.hpp Container emulator using iterator pairs +testsuite.cpp Python extension class for testing the container suite +slice_handler.hpp Python slice interpreter + + 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 @@ -9,13 +18,9 @@ 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 From 8e5400b8e490d7b0859ca6beefec862a23b89c53 Mon Sep 17 00:00:00 2001 From: Raoul Gough Date: Tue, 9 Sep 2003 20:56:09 +0000 Subject: [PATCH 10/39] Added working slice extraction [SVN r1516] --- .../python/suite/indexing/slice_handler.hpp | 110 ++++++++++++------ 1 file changed, 76 insertions(+), 34 deletions(-) diff --git a/include/boost/python/suite/indexing/slice_handler.hpp b/include/boost/python/suite/indexing/slice_handler.hpp index 357b9ec8..c9d5b4a0 100755 --- a/include/boost/python/suite/indexing/slice_handler.hpp +++ b/include/boost/python/suite/indexing/slice_handler.hpp @@ -26,21 +26,69 @@ #include #include +#include +#include // #include namespace indexing { - struct slice + class slice : public boost::python::object { - long start; - long step; // Extended slices (currently unsupported) - long stop; + int mStart; + int mStep; + int mStop; + bool mLengthSet; - // Implement from_python using: - // - // PySlice_GetIndices - // (PySliceObject *slice, int length, int *start, int *stop, int *step) + void validate () const { + if (!mLengthSet) + { + PyErr_SetString (PyExc_RuntimeError + , "slice access attempted before setLength called"); + boost::python::throw_error_already_set(); + } + } + + public: + slice (boost::python::detail::borrowed_reference ref) + : boost::python::object (ref) + , mStart (0) + , mStep (0) + , mStop (0) + , mLengthSet (false) + { + if (!PySlice_Check (this->ptr())) + { + PyErr_SetString (PyExc_TypeError + , "slice constructor: passed a non-slice object"); + + boost::python::throw_error_already_set(); + } + + // + // *** WARNING *** + // + // The slice object is useless until setLength is called + // + } + + void setLength (int sequenceLength) + { + PySlice_GetIndices ((PySliceObject *) this->ptr() + , sequenceLength + , &mStart + , &mStop + , &mStep); + + mStart = std::max (0, std::min (sequenceLength, mStart)); + mStop = std::max (0, std::min (sequenceLength, mStop)); + + mLengthSet = true; + } + + int start() const { validate(); return mStart; } + int step() const { validate(); return mStep; } + int stop() const { validate(); return mStop; } }; template @@ -51,47 +99,41 @@ namespace indexing typedef typename Algorithms::value_type value_type; typedef typename Algorithms::reference reference; - static PyObject *get_slice (container &c, slice const &sl) + static PyObject *get_slice (container &c, slice sl) { boost::python::list temp; - for (long index = sl.start; index < sl.stop; index += sl.step) + sl.setLength (Algorithms::size(c)); + + int direction = (sl.step() > 0) ? 1 : ((sl.step() == 0) ? 0 : -1); + + for (int index = sl.start() + ; ((sl.stop() - index) * direction) > 0 + ; index += sl.step()) { // *FIXME* handle return policies for each element? temp.append (Algorithms::get (c, index)); } - PyObject *result = list.ptr(); - Py_INCREF (result); + PyObject *result = temp.ptr(); + Py_INCREF (result); // ???? return result; } - static reference get_plain (container &c, index_param ix) - { - return Algorithms::get (c, ix); - } - - static PyObject *get_automatic (PyObject *args - , PyObject *keywords - , boost::python::object plain_function - , boost::python::object slice_function) - { - // ? - return 0; - } - static boost::python::object make_getitem (Policy const &policy) { - // ? Is there an easy way to generate a function that will - // call get_plain or get_slice depending on the arguments? - // - // Could be done by using get_automatic as a dispatcher, with - // the last two parameters bound to wrappers for the two - // implementations, but maybe there is a better way. - - return boost::python::make_function (get_plain, policy); + return boost::python::make_function (get_slice, policy); } }; } +namespace boost { namespace python { namespace converter { + // Specialized converter to handle PySlice_Type objects + template<> + struct object_manager_traits + : pytype_object_manager_traits<&PySlice_Type, ::indexing::slice> + { + }; +}}} + #endif // slice_handler_rmg_20030909_included From c63819dba968badcf0483789fa4eaa5b52337375 Mon Sep 17 00:00:00 2001 From: Raoul Gough Date: Tue, 9 Sep 2003 20:57:22 +0000 Subject: [PATCH 11/39] Define two overloads for __getitem__ in index_style_linear specialization [SVN r1517] --- include/boost/python/suite/indexing/container_suite.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/include/boost/python/suite/indexing/container_suite.hpp b/include/boost/python/suite/indexing/container_suite.hpp index 640736c1..07b081da 100755 --- a/include/boost/python/suite/indexing/container_suite.hpp +++ b/include/boost/python/suite/indexing/container_suite.hpp @@ -60,6 +60,7 @@ namespace indexing { , Algorithms const & , Policy const &policy) { + pyClass.def ("__getitem__", &Algorithms::get, policy); pyClass.def ("__getitem__" , slice_handler::make_getitem (policy)); } From 1279ed8ddfa47e09c5c92a8ab6e0c69a9e5c6df7 Mon Sep 17 00:00:00 2001 From: Raoul Gough Date: Tue, 9 Sep 2003 22:03:18 +0000 Subject: [PATCH 12/39] Tests for container_suite instance [SVN r1518] --- .../boost/python/suite/indexing/testarray.py | 35 ++++++++++++ .../boost/python/suite/indexing/testmap.py | 54 +++++++++++++++++++ .../boost/python/suite/indexing/testvector.py | 39 ++++++++++++++ 3 files changed, 128 insertions(+) create mode 100755 include/boost/python/suite/indexing/testarray.py create mode 100755 include/boost/python/suite/indexing/testmap.py create mode 100755 include/boost/python/suite/indexing/testvector.py diff --git a/include/boost/python/suite/indexing/testarray.py b/include/boost/python/suite/indexing/testarray.py new file mode 100755 index 00000000..ca85654f --- /dev/null +++ b/include/boost/python/suite/indexing/testarray.py @@ -0,0 +1,35 @@ +#!/usr/bin/python +# -*- mode:python -*- +# +# Python module testarray.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/ 9/ 9 rmg File creation +# +# $Id$ +# + +from testsuite import Array, getArray + +a = getArray() + +print a[0], a[1], a[2], [x for x in a], a[0:-2], a[-1:-3:-1], a[0:54:0] + +a[1] = 4 + +print a[0], a[1], a[2], [x for x in a], a[0:-2], a[-1:-3:-1] + +print a[0:43] diff --git a/include/boost/python/suite/indexing/testmap.py b/include/boost/python/suite/indexing/testmap.py new file mode 100755 index 00000000..79e12d9b --- /dev/null +++ b/include/boost/python/suite/indexing/testmap.py @@ -0,0 +1,54 @@ +#!/usr/bin/python +# -*- mode:python -*- +# +# Python module testmap.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/ 9/ 9 rmg File creation +# +# $Id$ +# + +from testsuite import Map + +m = Map() + +m["hello"] = 1 +m["there"] = 2 + +print m["hello"], m["there"] + +m["there"] = 3 + +print m["hello"], m["there"] + +try: + print [x for x in m] + +except TypeError, e: + print "Got semi-expected type error:", e + pass + +try: + print m["nonesuch"] + +except KeyError, e: + print "Got expected exception:", e + pass + +except Exception, e: + print "Got semi-expected exception:", e + pass diff --git a/include/boost/python/suite/indexing/testvector.py b/include/boost/python/suite/indexing/testvector.py new file mode 100755 index 00000000..4e4b161f --- /dev/null +++ b/include/boost/python/suite/indexing/testvector.py @@ -0,0 +1,39 @@ +#!/usr/bin/python +# -*- mode:python -*- +# +# Python module testvector.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/ 9/ 9 rmg File creation +# +# $Id$ +# + +from testsuite import Vector + +v = Vector() + +v.append(1) +v.append(2) +v.append(3) + +print v[0], v[1], v[2], [x for x in v] + +v[1] = 4 + +print v[0], v[1], v[2], [x for x in v] + +print v[0:2] From a6a88eb88ddd2b9500c63a1e3d7a3df57ab027d0 Mon Sep 17 00:00:00 2001 From: Raoul Gough Date: Wed, 10 Sep 2003 11:24:21 +0000 Subject: [PATCH 13/39] Simple int wrapper with optional tracing for test purposes [SVN r1519] --- .../python/suite/indexing/IntWrapper.cpp | 128 ++++++++++++++++++ .../python/suite/indexing/IntWrapper.hpp | 53 ++++++++ 2 files changed, 181 insertions(+) create mode 100755 include/boost/python/suite/indexing/IntWrapper.cpp create mode 100755 include/boost/python/suite/indexing/IntWrapper.hpp diff --git a/include/boost/python/suite/indexing/IntWrapper.cpp b/include/boost/python/suite/indexing/IntWrapper.cpp new file mode 100755 index 00000000..f5c6dc04 --- /dev/null +++ b/include/boost/python/suite/indexing/IntWrapper.cpp @@ -0,0 +1,128 @@ +// -*- mode:c++ -*- +// +// Module IntWrapper.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/ 9/10 rmg File creation +// +// $Id$ +// + +#include "IntWrapper.hpp" +#include + +bool IntWrapper::gIntWrapperTrace = true; + +unsigned IntWrapper::ourObjectCounter = 0; + +IntWrapper::IntWrapper () + : mObjNumber (ourObjectCounter++) + , mI (0) +{ + if (gIntWrapperTrace) + { + printf ("IntWrapper %u ()\n", mObjNumber); + } +} + +IntWrapper::IntWrapper (int i) + : mObjNumber (ourObjectCounter++) + , mI (i) +{ + if (gIntWrapperTrace) + { + printf ("IntWrapper %u (%d)\n" + , mObjNumber + , mI); + } +} + +IntWrapper::IntWrapper (IntWrapper const &other) + : mObjNumber (ourObjectCounter++) + , mI (other.mI) +{ + if (gIntWrapperTrace) + { + printf ("IntWrapper %u (IntWrapper %u)\n" + , mObjNumber + , other.mObjNumber); + } +} + +IntWrapper &IntWrapper::operator= (IntWrapper const &other) +{ + if (gIntWrapperTrace) + { + printf ("IntWrapper %u = IntWrapper %u\n" + , mObjNumber + , other.mObjNumber); + } + + mI = other.mI; + + return *this; +} + +IntWrapper::~IntWrapper () +{ + if (gIntWrapperTrace) + { + printf ("~IntWrapper %u\n", mObjNumber); + } + + mI = 0xbaaaaaad; +} + +void IntWrapper::increment() +{ + if (gIntWrapperTrace) + { + printf ("IntWrapper %u::increment\n", mObjNumber); + } + + ++mI; +} + +IntWrapper::operator boost::shared_ptr () const +{ + if (gIntWrapperTrace) + { + printf ("IntWrapper %u shared_ptr conversion\n", mObjNumber); + } + + return boost::shared_ptr (new IntWrapper (*this)); +} + +void IntWrapper::setTrace (int onoff) +{ + gIntWrapperTrace = onoff; +} + +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; +} diff --git a/include/boost/python/suite/indexing/IntWrapper.hpp b/include/boost/python/suite/indexing/IntWrapper.hpp new file mode 100755 index 00000000..c992063f --- /dev/null +++ b/include/boost/python/suite/indexing/IntWrapper.hpp @@ -0,0 +1,53 @@ +// -*- mode:c++ -*- +// +// Header file IntWrapper.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/ 9/10 rmg File creation +// +// $Id$ +// + +#ifndef IntWrapper_rmg_20030910_included +#define IntWrapper_rmg_20030910_included + +#include +#include + +struct IntWrapper { + static bool gIntWrapperTrace; + static unsigned ourObjectCounter; + int mObjNumber; + int mI; + + IntWrapper (); + explicit IntWrapper (int i); + IntWrapper (IntWrapper const &other); + IntWrapper &operator= (IntWrapper const &other); + ~IntWrapper (); + + void increment(); + + operator boost::shared_ptr () const; + + static void setTrace (int onoff); +}; + +bool operator== (IntWrapper const &lhs, IntWrapper const &rhs); +bool operator< (IntWrapper const &lhs, IntWrapper const &rhs); +std::ostream &operator<< (std::ostream &strm, IntWrapper const &iw); + +#endif // IntWrapper_rmg_20030910_included From dcf0cdf35b7d26d55182882f77039c43ad6a195c Mon Sep 17 00:00:00 2001 From: Raoul Gough Date: Wed, 10 Sep 2003 11:24:47 +0000 Subject: [PATCH 14/39] Split IntWrapper into separate module [SVN r1520] --- .../boost/python/suite/indexing/indexing.cpp | 112 +----------------- 1 file changed, 2 insertions(+), 110 deletions(-) diff --git a/include/boost/python/suite/indexing/indexing.cpp b/include/boost/python/suite/indexing/indexing.cpp index aba20e38..b7582e20 100755 --- a/include/boost/python/suite/indexing/indexing.cpp +++ b/include/boost/python/suite/indexing/indexing.cpp @@ -22,6 +22,7 @@ // #include "container_proxy.hpp" +#include "IntWrapper.hpp" #include #include @@ -34,110 +35,6 @@ #include #include -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 () const - { - if (gIntWrapperTrace) - { - printf ("IntWrapper %u shared_ptr conversion\n", mObjNumber); - } - - return boost::shared_ptr (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 std::string proxy_repr (typename ContainerProxy::value_type const &proxy) { @@ -160,11 +57,6 @@ void pointer_increment (boost::shared_ptr const &ptr) (*ptr).increment(); } -void setTrace (int onoff) -{ - gIntWrapperTrace = onoff; -} - IntWrapper *get_pointer (container_proxy >::value_type const &proxy) { return &(*proxy); @@ -172,7 +64,7 @@ IntWrapper *get_pointer (container_proxy >::value_type c BOOST_PYTHON_MODULE (indexing) { - boost::python::def ("trace", &setTrace); + boost::python::def ("trace", &IntWrapper::setTrace); typedef std::vector Container; typedef container_proxy ProxyContainer; From 5f3579bc040c003ddffba2c0a09a888872bd3136 Mon Sep 17 00:00:00 2001 From: Raoul Gough Date: Wed, 10 Sep 2003 11:25:24 +0000 Subject: [PATCH 15/39] Add call policies support to get_slice [SVN r1521] --- .../python/suite/indexing/slice_handler.hpp | 52 ++++++++++++++++--- 1 file changed, 45 insertions(+), 7 deletions(-) diff --git a/include/boost/python/suite/indexing/slice_handler.hpp b/include/boost/python/suite/indexing/slice_handler.hpp index c9d5b4a0..38237f99 100755 --- a/include/boost/python/suite/indexing/slice_handler.hpp +++ b/include/boost/python/suite/indexing/slice_handler.hpp @@ -27,6 +27,7 @@ #include #include #include +#include #include // #include @@ -99,9 +100,46 @@ namespace indexing typedef typename Algorithms::value_type value_type; typedef typename Algorithms::reference reference; - static PyObject *get_slice (container &c, slice sl) + class postcall_override { - boost::python::list temp; + // This class overrides our Policy's postcall function and + // result_conveter to handle the list returned from get_slice. + // The Policy's result_converter is removed, since it gets + // applied within get_slice. Our postcall override applies the + // original postcall to each element of the Python list returned + // from get_slice. + + Policy mBase; + + public: + postcall_override (Policy const &p) : mBase (p) { + } + + bool precall (PyObject *args) { + return mBase.precall (args); + } + + PyObject* postcall (PyObject *args, PyObject *result) { + int size = PyList_Size (result); + + for (int count = 0; count < size; ++count) + { + mBase.postcall (args, PyList_GetItem (result, count)); + } + + return result; + } + + typedef boost::python::default_result_converter result_converter; + }; + + static boost::python::list get_slice (container &c, slice sl) + { + typedef typename Policy::result_converter converter_type; + typedef typename Algorithms::reference reference; + typename boost::mpl::apply1::type converter; + + boost::python::list result; sl.setLength (Algorithms::size(c)); @@ -111,18 +149,18 @@ namespace indexing ; ((sl.stop() - index) * direction) > 0 ; index += sl.step()) { - // *FIXME* handle return policies for each element? - temp.append (Algorithms::get (c, index)); + result.append + (boost::python::handle<> + (converter (Algorithms::get (c, index)))); } - PyObject *result = temp.ptr(); - Py_INCREF (result); // ???? return result; } static boost::python::object make_getitem (Policy const &policy) { - return boost::python::make_function (get_slice, policy); + return boost::python::make_function + (get_slice, postcall_override (policy)); } }; } From e362ad5545ae7adfa4e9280aeb2341843ba491f8 Mon Sep 17 00:00:00 2001 From: Raoul Gough Date: Wed, 10 Sep 2003 11:25:54 +0000 Subject: [PATCH 16/39] Support for client-provided call policies using generator function [SVN r1522] --- .../python/suite/indexing/container_suite.hpp | 46 ++++++++++++++----- 1 file changed, 35 insertions(+), 11 deletions(-) diff --git a/include/boost/python/suite/indexing/container_suite.hpp b/include/boost/python/suite/indexing/container_suite.hpp index 07b081da..e75bffbf 100755 --- a/include/boost/python/suite/indexing/container_suite.hpp +++ b/include/boost/python/suite/indexing/container_suite.hpp @@ -131,32 +131,56 @@ namespace indexing { } }; - template > - struct container_suite - : public boost::python::def_visitor > + template + class container_suite_impl + : public boost::python::def_visitor > { + Policy mPolicy; + + public: typedef typename Traits::algorithms algorithms; typedef typename Traits::reference reference_return; + typedef Policy return_policy; - typedef boost::python::return_value_policy - return_policy; + container_suite_impl (Policy const &policy) : mPolicy (policy) { } template - static void visit (PythonClass &pyClass) + void visit (PythonClass &pyClass) const { maybe_add_getitem - ::apply (pyClass, algorithms(), return_policy()); + ::apply (pyClass, algorithms(), mPolicy); maybe_add_setitem - ::apply (pyClass, algorithms(), return_policy()); + ::apply (pyClass, algorithms(), mPolicy); maybe_add_iter<((Traits::index_style != index_style_linear) && Traits::has_copyable_iter)> - ::apply (pyClass, algorithms(), return_policy()); + ::apply (pyClass, algorithms(), mPolicy); maybe_add_append - ::apply (pyClass, algorithms(), return_policy()); + ::apply (pyClass, algorithms(), mPolicy); + } + }; + + template > + struct container_suite + { + typedef boost::python::return_value_policy + default_policies; + + static + container_suite_impl + generate () + { + return container_suite_impl (default_policies()); + } + + template + static + container_suite_impl + generate (Policy const &policy) + { + return container_suite_impl (policy); } }; } From ea5fa8ab3e53cdcc74490c34b1ef67430ad7e941 Mon Sep 17 00:00:00 2001 From: Raoul Gough Date: Wed, 10 Sep 2003 11:26:31 +0000 Subject: [PATCH 17/39] Use IntWrapper for tracing, provide Vector_ref with return_internal_refrerence policy [SVN r1523] --- .../boost/python/suite/indexing/testsuite.cpp | 56 ++++++++++++++----- 1 file changed, 43 insertions(+), 13 deletions(-) diff --git a/include/boost/python/suite/indexing/testsuite.cpp b/include/boost/python/suite/indexing/testsuite.cpp index 426b3e0d..758462dc 100755 --- a/include/boost/python/suite/indexing/testsuite.cpp +++ b/include/boost/python/suite/indexing/testsuite.cpp @@ -22,46 +22,76 @@ // #include "container_suite.hpp" +#include "IntWrapper.hpp" #include #include #include +#include +#include + #include #include #include +#include #include "iterator_pair.hpp" -indexing::iterator_pair getArray() +indexing::iterator_pair getArray() { - static int array[] = { 8, 7, 6, 5, 4, 3, 2, 1, 0 }; + static IntWrapper array[] = { + IntWrapper(8), IntWrapper(7), IntWrapper(6), IntWrapper(5) + , IntWrapper(4), IntWrapper(3), IntWrapper(2) + , IntWrapper(1), IntWrapper(0) }; - return indexing::iterator_pair(indexing::begin(array) - , indexing::end(array)); + return indexing::iterator_pair(indexing::begin(array) + , indexing::end(array)); +} + +std::string repr (IntWrapper const &i) +{ + std::stringstream temp; + temp << i; + return temp.str(); } BOOST_PYTHON_MODULE(testsuite) { + boost::python::implicitly_convertible (); + + boost::python::class_ ("IntWrapper", boost::python::init()) + .def ("increment", &IntWrapper::increment) + .def ("__repr__", repr); + ; + typedef std::vector Container1; boost::python::class_("Vector") - .def (indexing::container_suite()); + .def (indexing::container_suite::generate()); - typedef std::list Container2; + typedef std::list Container2; boost::python::class_("List") - .def (indexing::container_suite()); + .def (indexing::container_suite::generate()); - typedef std::map Container3; + typedef std::map Container3; boost::python::class_("Map") - .def (indexing::container_suite()); + .def (indexing::container_suite::generate()); - typedef indexing::iterator_pair Container4; + typedef indexing::iterator_pair Container4; - boost::python::class_("Array" - , boost::python::init()) - .def (indexing::container_suite()); + boost::python::class_ + ("Array", boost::python::init()) + .def (indexing::container_suite::generate()); boost::python::def ("getArray", getArray); + + typedef std::vector Container5; + + // Returning internal references to elements of a vector is + // dangerous! The references can be invalidated by inserts or + // deletes! + boost::python::class_("Vector_ref") + .def (indexing::container_suite::generate (boost::python::return_internal_reference<>())); } From a8d2e3cc26a8562bc0c3482e6db7cba13518f287 Mon Sep 17 00:00:00 2001 From: Raoul Gough Date: Wed, 10 Sep 2003 15:36:45 +0000 Subject: [PATCH 18/39] C++ interface to iterable Python objects [SVN r1524] --- .../python/suite/indexing/python_iterator.cpp | 172 ++++++++++++++++++ .../python/suite/indexing/python_iterator.hpp | 71 ++++++++ 2 files changed, 243 insertions(+) create mode 100755 include/boost/python/suite/indexing/python_iterator.cpp create mode 100755 include/boost/python/suite/indexing/python_iterator.hpp diff --git a/include/boost/python/suite/indexing/python_iterator.cpp b/include/boost/python/suite/indexing/python_iterator.cpp new file mode 100755 index 00000000..1dd81112 --- /dev/null +++ b/include/boost/python/suite/indexing/python_iterator.cpp @@ -0,0 +1,172 @@ +// -*- mode:c++ -*- +// +// Module python_iterator.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/ 9/10 rmg File creation +// +// $Id$ +// + +#include "python_iterator.hpp" + +//////////////////////////////////////////////////////////////////////////// +// python_iterator factory +/////////////////////////////////////////////////////////////////////////// + +std::auto_ptr +indexing::make_iterator (boost::python::object temp) +{ + std::auto_ptr result; + + try + { + result.reset (new python_iter_iterator (temp)); + } + + catch (boost::python::error_already_set const &) + { + PyErr_Clear (); + + try + { + result.reset (new python_getitem_iterator (temp)); + } + + catch (boost::python::error_already_set const &) + { + PyErr_Clear (); + } + } + + return result; +} + +//////////////////////////////////////////////////////////////////////////// +// Base class (virtual) destructor +/////////////////////////////////////////////////////////////////////////// + +indexing::python_iterator::~python_iterator () +{ +} + +//////////////////////////////////////////////////////////////////////////// +// python_getitem_iterator constructor +/////////////////////////////////////////////////////////////////////////// + +indexing::python_getitem_iterator +::python_getitem_iterator (boost::python::object obj) + : mGetitemMethod (obj.attr ("__getitem__")) + , mIndex (0) + , mCurrent() +{ +} + +//////////////////////////////////////////////////////////////////////////// +// Get our next item (if any) +/////////////////////////////////////////////////////////////////////////// + +bool indexing::python_getitem_iterator::next () +{ + bool result = true; // Assume success + + try + { + mCurrent = mGetitemMethod (mIndex); + ++mIndex; + } + + catch (boost::python::error_already_set const &) + { + if (PyErr_ExceptionMatches (PyExc_IndexError)) + { + // Eat this exception + PyErr_Clear (); + mCurrent = boost::python::object (); + result = false; + } + + else + { + // Pass it up the line + throw; + } + } + + return result; +} + +//////////////////////////////////////////////////////////////////////////// +// Return our current item +/////////////////////////////////////////////////////////////////////////// + +boost::python::object indexing::python_getitem_iterator::current () const +{ + return mCurrent; +} + +//////////////////////////////////////////////////////////////////////////// +// python_iter_iterator constructor +/////////////////////////////////////////////////////////////////////////// + +indexing::python_iter_iterator +::python_iter_iterator (boost::python::object obj) + : mNextMethod (obj.attr ("__iter__")().attr ("next")) + , mCurrent() +{ +} + +//////////////////////////////////////////////////////////////////////////// +// Get our next item (if any) +/////////////////////////////////////////////////////////////////////////// + +bool indexing::python_iter_iterator::next () +{ + bool result = true; // Assume success + + try + { + mCurrent = mNextMethod (); + } + + catch (boost::python::error_already_set const &) + { + if (PyErr_ExceptionMatches (PyExc_StopIteration)) + { + // Eat this exception + PyErr_Clear (); + mCurrent = boost::python::object (); + result = false; + } + + else + { + // Pass it up the line + throw; + } + } + + return result; +} + +//////////////////////////////////////////////////////////////////////////// +// Return our current item +/////////////////////////////////////////////////////////////////////////// + +boost::python::object indexing::python_iter_iterator::current () const +{ + return mCurrent; +} diff --git a/include/boost/python/suite/indexing/python_iterator.hpp b/include/boost/python/suite/indexing/python_iterator.hpp new file mode 100755 index 00000000..d1fcf41c --- /dev/null +++ b/include/boost/python/suite/indexing/python_iterator.hpp @@ -0,0 +1,71 @@ +// -*- mode:c++ -*- +// +// Header file python_iterator.hpp +// +// Handy Python iterable iterators +// +// 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/ 9/10 rmg File creation +// +// $Id$ +// + +#ifndef python_iterator_rmg_20030910_included +#define python_iterator_rmg_20030910_included + +#include +#include + +namespace indexing { + struct python_iterator + { + virtual ~python_iterator (); + virtual bool next () = 0; + virtual boost::python::object current() const = 0; + }; + + std::auto_ptr make_iterator (boost::python::object); + // Returns null auto_ptr if object does not provide __iter__ nor + // __getitem__, otherwise a pointer to a suitable implementation of + // python_iterator + + struct python_getitem_iterator : public python_iterator + { + public: + python_getitem_iterator (boost::python::object); + virtual bool next (); + virtual boost::python::object current() const; + + private: + boost::python::object mGetitemMethod; + int mIndex; + boost::python::object mCurrent; + }; + + struct python_iter_iterator : public python_iterator + { + public: + python_iter_iterator (boost::python::object); + virtual bool next (); + virtual boost::python::object current() const; + + private: + boost::python::object mNextMethod; + boost::python::object mCurrent; + }; +} + +#endif // python_iterator_rmg_20030910_included From f587a1b684a72f27a1cee482db1aa6d3851f838a Mon Sep 17 00:00:00 2001 From: Raoul Gough Date: Wed, 10 Sep 2003 15:37:45 +0000 Subject: [PATCH 19/39] TypeWrapper for Python slice objects [SVN r1525] --- include/boost/python/suite/indexing/slice.cpp | 93 +++++++++++++++++++ include/boost/python/suite/indexing/slice.hpp | 71 ++++++++++++++ 2 files changed, 164 insertions(+) create mode 100755 include/boost/python/suite/indexing/slice.cpp create mode 100755 include/boost/python/suite/indexing/slice.hpp diff --git a/include/boost/python/suite/indexing/slice.cpp b/include/boost/python/suite/indexing/slice.cpp new file mode 100755 index 00000000..3247860b --- /dev/null +++ b/include/boost/python/suite/indexing/slice.cpp @@ -0,0 +1,93 @@ +// -*- mode:c++ -*- +// +// Module slice.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/ 9/10 rmg File creation +// +// $Id$ +// + +#include "slice.hpp" + +///////////////////////////////////////////////////////////////////////////// +// Check that setLength has been called, and throw otherwise +///////////////////////////////////////////////////////////////////////////// + +void indexing::slice::validate () const +{ + if (mDirection == 0) + { + PyErr_SetString (PyExc_RuntimeError + , "slice access attempted before setLength called"); + boost::python::throw_error_already_set(); + } +} + +///////////////////////////////////////////////////////////////////////////// +// Slice constructor +///////////////////////////////////////////////////////////////////////////// + +indexing::slice::slice (boost::python::detail::borrowed_reference ref) + : boost::python::object (ref) + , mStart (0) + , mStep (0) + , mStop (0) + , mDirection (0) +{ + if (!PySlice_Check (this->ptr())) + { + PyErr_SetString (PyExc_TypeError + , "slice constructor: passed a non-slice object"); + + boost::python::throw_error_already_set(); + } + + // This slice object is useless until setLength is called +} + +///////////////////////////////////////////////////////////////////////////// +// Set up our member variables for a sequence of a given length +///////////////////////////////////////////////////////////////////////////// + +void indexing::slice::setLength (int sequenceLength) +{ + PySlice_GetIndices ((PySliceObject *) this->ptr() + , sequenceLength + , &mStart + , &mStop + , &mStep); + + if (mStep == 0) + { + // Can happen with Python prior to 2.3 + PyErr_SetString (PyExc_ValueError, "slice step cannot be zero"); + boost::python::throw_error_already_set (); + } + + mStart = std::max (0, std::min (sequenceLength, mStart)); + mStop = std::max (0, std::min (sequenceLength, mStop)); + mDirection = (mStep > 0) ? 1 : -1; +} + +///////////////////////////////////////////////////////////////////////////// +// Check if an index is within the range of this slice +///////////////////////////////////////////////////////////////////////////// + +bool indexing::slice::inRange (int index) +{ + return ((mStop - index) * mDirection) > 0; +} diff --git a/include/boost/python/suite/indexing/slice.hpp b/include/boost/python/suite/indexing/slice.hpp new file mode 100755 index 00000000..3c626a01 --- /dev/null +++ b/include/boost/python/suite/indexing/slice.hpp @@ -0,0 +1,71 @@ +// -*- mode:c++ -*- +// +// Header file slice.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/ 9/10 rmg File creation +// +// $Id$ +// + +#ifndef slice_rmg_20030910_included +#define slice_rmg_20030910_included + +#include +#include +#include + +namespace indexing +{ + struct slice : public boost::python::object + { + // + // *** WARNING *** + // + // A newly constructed slice object is useless until setLength is called + // + + slice (boost::python::detail::borrowed_reference ref); + void setLength (int sequenceLength); + + int start() const { validate(); return mStart; } + int step() const { validate(); return mStep; } + int stop() const { validate(); return mStop; } + + int size() const { validate(); return (mStop - mStart) / mStep; } + + bool inRange (int index); + + private: + void validate () const; // throws unless setLength has been called + + int mStart; + int mStep; + int mStop; + int mDirection; + }; +} + +namespace boost { namespace python { namespace converter { + // Specialized converter to handle PySlice_Type objects + template<> + struct object_manager_traits + : pytype_object_manager_traits<&PySlice_Type, ::indexing::slice> + { + }; +}}} + +#endif // slice_rmg_20030910_included From de1ea325bd16e949633cef82fcf173d2cc0fc333 Mon Sep 17 00:00:00 2001 From: Raoul Gough Date: Wed, 10 Sep 2003 15:38:52 +0000 Subject: [PATCH 20/39] Added __setitem__ overload for slice handling [SVN r1526] --- include/boost/python/suite/indexing/container_suite.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/boost/python/suite/indexing/container_suite.hpp b/include/boost/python/suite/indexing/container_suite.hpp index e75bffbf..517692a2 100755 --- a/include/boost/python/suite/indexing/container_suite.hpp +++ b/include/boost/python/suite/indexing/container_suite.hpp @@ -91,7 +91,8 @@ namespace indexing { , Policy const &policy) { pyClass.def ("__setitem__", &Algorithms::assign, policy); - // *FIXME* add slicing support + pyClass.def ("__setitem__" + , slice_handler::make_setitem (policy)); } }; From a8eb3979ee0bbd4ce0ab5904077f0ad4d02e16f4 Mon Sep 17 00:00:00 2001 From: Raoul Gough Date: Wed, 10 Sep 2003 15:39:31 +0000 Subject: [PATCH 21/39] Added setTrace def [SVN r1527] --- include/boost/python/suite/indexing/testsuite.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/boost/python/suite/indexing/testsuite.cpp b/include/boost/python/suite/indexing/testsuite.cpp index 758462dc..2f11aa2d 100755 --- a/include/boost/python/suite/indexing/testsuite.cpp +++ b/include/boost/python/suite/indexing/testsuite.cpp @@ -59,6 +59,8 @@ BOOST_PYTHON_MODULE(testsuite) { boost::python::implicitly_convertible (); + boost::python::def ("setTrace", &IntWrapper::setTrace); + boost::python::class_ ("IntWrapper", boost::python::init()) .def ("increment", &IntWrapper::increment) .def ("__repr__", repr); From 2c8f4753e2406ee2a69bad618bebd54087ad55a3 Mon Sep 17 00:00:00 2001 From: Raoul Gough Date: Wed, 10 Sep 2003 15:40:38 +0000 Subject: [PATCH 22/39] Remove slice to separate file, out of line function bodies, working set_slice [SVN r1528] --- .../python/suite/indexing/slice_handler.hpp | 349 ++++++++++++------ 1 file changed, 234 insertions(+), 115 deletions(-) diff --git a/include/boost/python/suite/indexing/slice_handler.hpp b/include/boost/python/suite/indexing/slice_handler.hpp index 38237f99..62a2e80d 100755 --- a/include/boost/python/suite/indexing/slice_handler.hpp +++ b/include/boost/python/suite/indexing/slice_handler.hpp @@ -26,81 +26,29 @@ #include #include -#include +#include #include #include -// #include +#include "slice.hpp" +#include "python_iterator.hpp" namespace indexing { - class slice : public boost::python::object - { - int mStart; - int mStep; - int mStop; - bool mLengthSet; - - void validate () const { - if (!mLengthSet) - { - PyErr_SetString (PyExc_RuntimeError - , "slice access attempted before setLength called"); - boost::python::throw_error_already_set(); - } - } - - public: - slice (boost::python::detail::borrowed_reference ref) - : boost::python::object (ref) - , mStart (0) - , mStep (0) - , mStop (0) - , mLengthSet (false) - { - if (!PySlice_Check (this->ptr())) - { - PyErr_SetString (PyExc_TypeError - , "slice constructor: passed a non-slice object"); - - boost::python::throw_error_already_set(); - } - - // - // *** WARNING *** - // - // The slice object is useless until setLength is called - // - } - - void setLength (int sequenceLength) - { - PySlice_GetIndices ((PySliceObject *) this->ptr() - , sequenceLength - , &mStart - , &mStop - , &mStep); - - mStart = std::max (0, std::min (sequenceLength, mStart)); - mStop = std::max (0, std::min (sequenceLength, mStop)); - - mLengthSet = true; - } - - int start() const { validate(); return mStart; } - int step() const { validate(); return mStep; } - int stop() const { validate(); return mStop; } - }; - template struct slice_handler { + static boost::python::object make_getitem (Policy const &); + static boost::python::object make_setitem (Policy const &); + + private: typedef typename Algorithms::container container; - typedef typename Algorithms::index_param index_param; - typedef typename Algorithms::value_type value_type; typedef typename Algorithms::reference reference; - class postcall_override + static boost::python::list get_slice (container &, slice); + static void set_slice (container &, slice, boost::python::object); + + struct postcall_override { // This class overrides our Policy's postcall function and // result_conveter to handle the list returned from get_slice. @@ -109,69 +57,240 @@ namespace indexing // original postcall to each element of the Python list returned // from get_slice. - Policy mBase; - - public: - postcall_override (Policy const &p) : mBase (p) { - } - - bool precall (PyObject *args) { - return mBase.precall (args); - } - - PyObject* postcall (PyObject *args, PyObject *result) { - int size = PyList_Size (result); - - for (int count = 0; count < size; ++count) - { - mBase.postcall (args, PyList_GetItem (result, count)); - } - - return result; - } - typedef boost::python::default_result_converter result_converter; + + postcall_override (Policy const &p); + + bool precall (PyObject *args); + PyObject* postcall (PyObject *args, PyObject *result); + + private: + Policy mBase; }; + }; - static boost::python::list get_slice (container &c, slice sl) + template struct maybe_insert { + template + static void apply (typename Algorithms::container & + , typename Algorithms::index_param + , typename Algorithms::value_param) { - typedef typename Policy::result_converter converter_type; - typedef typename Algorithms::reference reference; - typename boost::mpl::apply1::type converter; + PyErr_SetString (PyExc_TypeError + , "container does not support item insertion"); - boost::python::list result; - - sl.setLength (Algorithms::size(c)); - - int direction = (sl.step() > 0) ? 1 : ((sl.step() == 0) ? 0 : -1); - - for (int index = sl.start() - ; ((sl.stop() - index) * direction) > 0 - ; index += sl.step()) - { - result.append - (boost::python::handle<> - (converter (Algorithms::get (c, index)))); - } - - return result; + boost::python::throw_error_already_set (); } + }; - static boost::python::object make_getitem (Policy const &policy) + template<> struct maybe_insert { + template + static void apply (typename Algorithms::container &c + , typename Algorithms::index_param i + , typename Algorithms::value_param v) { - return boost::python::make_function - (get_slice, postcall_override (policy)); + Algorithms::insert (c, i, v); + } + }; + + template struct maybe_erase { + template + static void apply (typename Algorithms::container & + , typename Algorithms::index_param + , typename Algorithms::index_param) + { + PyErr_SetString (PyExc_TypeError + , "container does not support item deletion"); + + boost::python::throw_error_already_set (); + } + }; + + template<> struct maybe_erase { + template + static void apply (typename Algorithms::container &c + , typename Algorithms::index_param from + , typename Algorithms::index_param to) + { + Algorithms::erase (c, from, to); } }; } -namespace boost { namespace python { namespace converter { - // Specialized converter to handle PySlice_Type objects - template<> - struct object_manager_traits - : pytype_object_manager_traits<&PySlice_Type, ::indexing::slice> - { - }; -}}} +///////////////////////////////////////////////////////////////////////////// +// postcall_override constructor +///////////////////////////////////////////////////////////////////////////// + +template +indexing::slice_handler +::postcall_override::postcall_override (Policy const &p) + : mBase (p) +{ +} + +///////////////////////////////////////////////////////////////////////////// +// precall forwarder +///////////////////////////////////////////////////////////////////////////// + +template +bool +indexing::slice_handler +::postcall_override::precall (PyObject *args) +{ + return mBase.precall (args); +} + +///////////////////////////////////////////////////////////////////////////// +// Apply base postcall to each element of the list returend by get_slice +///////////////////////////////////////////////////////////////////////////// + +template +PyObject * +indexing::slice_handler +::postcall_override::postcall (PyObject *args, PyObject *result) +{ + int size = PyList_Size (result); + + for (int count = 0; count < size; ++count) + { + mBase.postcall (args, PyList_GetItem (result, count)); + } + + return result; +} + +///////////////////////////////////////////////////////////////////////////// +// Return a function object that implements the slice version of __getitem__ +///////////////////////////////////////////////////////////////////////////// + +template +boost::python::object +indexing::slice_handler +::make_getitem (Policy const &policy) +{ + return boost::python::make_function (get_slice, postcall_override (policy)); +} + +///////////////////////////////////////////////////////////////////////////// +// Return a function object that implements the slice version of __setitem__ +///////////////////////////////////////////////////////////////////////////// + +template +boost::python::object +indexing::slice_handler +::make_setitem (Policy const &policy) +{ + // should we try to get funky with policy::precall? + return boost::python::make_function (set_slice, policy); +} + +///////////////////////////////////////////////////////////////////////////// +// Implementation for the slice version of __getitem__ +///////////////////////////////////////////////////////////////////////////// + +template +boost::python::list +indexing::slice_handler +::get_slice (container &c, slice sl) +{ + typedef typename Policy::result_converter converter_type; + typedef typename Algorithms::reference reference; + typename boost::mpl::apply1::type converter; + + boost::python::list result; + + sl.setLength (Algorithms::size(c)); + + for (int index = sl.start(); sl.inRange (index); index += sl.step()) + { + // Apply the result converter (only) to each element before + // appending. postcall is done in postcall_override + + result.append + (boost::python::handle<> + (converter (Algorithms::get (c, index)))); + } + + return result; +} + +///////////////////////////////////////////////////////////////////////////// +// Implementation for the slice version of __setitem__ +///////////////////////////////////////////////////////////////////////////// + +template +void +indexing::slice_handler +::set_slice (container &c, slice sl, boost::python::object values) +{ + std::auto_ptr iterPtr (make_iterator (values)); + + if (!iterPtr.get()) + { + PyErr_SetString (PyExc_TypeError + , "Type assigned to slice must be a sequence"); + + boost::python::throw_error_already_set(); + } + + typedef typename Algorithms::container_traits traits; + typedef boost::python::extract extractor; + + // Note: any error during this operation will probably leave the + // container partially updated. This can occur (for example) if the + // replacement sequence is of a different length to the original + // slice and the container does not support insertion/deletion. + // This could be prevented if the length of the replacement sequence + // is known in advance (via __len__, for example) but not otherwise. + + sl.setLength (Algorithms::size (c)); // Current length of our container + int index = sl.start(); // Index in our container for update + + // Overwrite and/or insert elements + while (iterPtr->next()) + { + if (sl.inRange (index)) + { + Algorithms::assign (c, index, extractor (iterPtr->current())); + } + + else if (sl.step() != 1) + { + PyErr_SetString (PyExc_ValueError + , "attempt to insert via extended slice"); + + boost::python::throw_error_already_set (); + } + + else + { + // Could optimize this in some cases (i.e. if the length of + // the replacement sequence is known) + + maybe_insert + ::template apply (c, index + , extractor (iterPtr->current())); + } + + index += sl.step(); + } + + // Erase any remaining elements in the slice + if (sl.inRange(index)) + { + if (sl.step() != 1) + { + PyErr_SetString (PyExc_ValueError + , "attempt to erase via extended slice"); + + boost::python::throw_error_already_set (); + } + + else + { + maybe_erase + ::template apply (c, index, sl.stop()); + } + } +} #endif // slice_handler_rmg_20030909_included From 415be6e71a9afda489b5c8bccceb3412bf640810 Mon Sep 17 00:00:00 2001 From: Raoul Gough Date: Thu, 11 Sep 2003 22:32:54 +0000 Subject: [PATCH 23/39] Uniform interface layer for various containers [SVN r1532] --- .../python/suite/indexing/algorithms.hpp | 311 ++++++++++++++++++ 1 file changed, 311 insertions(+) create mode 100755 include/boost/python/suite/indexing/algorithms.hpp diff --git a/include/boost/python/suite/indexing/algorithms.hpp b/include/boost/python/suite/indexing/algorithms.hpp new file mode 100755 index 00000000..7c44582c --- /dev/null +++ b/include/boost/python/suite/indexing/algorithms.hpp @@ -0,0 +1,311 @@ +// -*- mode:c++ -*- +// +// Header file algorithms.hpp +// +// Uniform interface layer for all containers. +// +// 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/ 9/11 rmg File creation from suite_utils.hpp +// +// $Id$ +// + +#ifndef algorithms_rmg_20030823_included +#define algorithms_rmg_20030823_included + +#include "suite_utils.hpp" +#include +#include +#include +#include +#include + +namespace indexing { + template + struct default_algorithms + { + typedef ContainerTraits container_traits; + + typedef typename ContainerTraits::container container; + typedef typename ContainerTraits::iterator iterator; + typedef typename ContainerTraits::reference reference; + typedef typename ContainerTraits::key_type key_type; + typedef typename ContainerTraits::size_type size_type; + typedef typename ContainerTraits::index_type index_type; + typedef typename ContainerTraits::value_type value_type; + + typedef typename boost::call_traits::param_type value_param; + typedef typename boost::call_traits::param_type key_param; + typedef typename boost::call_traits::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 reference get (container &, index_param); + static void assign (container &, index_param, value_param); + static void insert (container &, index_param, value_param); + static void erase (container &, index_param, index_param); + static void push_back (container &, value_param); + static void sort (container &); + // static void sort (container &, PyObject *); + + static iterator begin (container &c) { return c.begin(); } + static iterator end (container &c) { return c.end(); } + }; + + ///////////////////////////////////////////////////////////////////////// + // Get the size of a container + ///////////////////////////////////////////////////////////////////////// + + template + typename default_algorithms::size_type + default_algorithms::size (container &c) + { + return c.size(); + } + + ///////////////////////////////////////////////////////////////////////// + // Find an element in a container (std algorithm version) + ///////////////////////////////////////////////////////////////////////// + + template + typename default_algorithms::iterator + default_algorithms::find (container &c + , key_param key) + { + return std::find (begin(c), end(c), key); + } + + ///////////////////////////////////////////////////////////////////////// + // Count occurances of an element in a container (std algorithm version) + ///////////////////////////////////////////////////////////////////////// + + template + typename default_algorithms::size_type + default_algorithms::count (container &c + , key_param key) + { + return std::count (begin(c), end(c), key); + } + + ///////////////////////////////////////////////////////////////////////// + // Index into a container (generic version) + ///////////////////////////////////////////////////////////////////////// + + template + typename default_algorithms::reference + default_algorithms::get (container &c, index_param ix) + { + return c.at (ix); + } + + ///////////////////////////////////////////////////////////////////////// + // Assign a value at a particular index (generic version) + ///////////////////////////////////////////////////////////////////////// + + template + void + default_algorithms::assign (container &c + , index_param ix + , value_param val) + { + c.at(ix) = val; + } + + ///////////////////////////////////////////////////////////////////////// + // Insert at end of a container (generic version) + ///////////////////////////////////////////////////////////////////////// + + template + void + default_algorithms::push_back (container &c + , value_param v) + { + c.push_back (v); + } + + ///////////////////////////////////////////////////////////////////////// + // Insert at an index in the container (generic version) + ///////////////////////////////////////////////////////////////////////// + + template + void + default_algorithms::insert (container &c + , index_param i + , value_param v) + { + c.insert (c.begin() + i, v); + } + + ///////////////////////////////////////////////////////////////////////// + // Erase between given indexes in the container (generic version) + ///////////////////////////////////////////////////////////////////////// + + template + void + default_algorithms::erase (container &c + , index_param from + , index_param to) + { + c.erase (c.begin() + from, c.begin() + to); + } + + ///////////////////////////////////////////////////////////////////////// + // Reverse the contents of a container (std algorithm version) + ///////////////////////////////////////////////////////////////////////// + + template + void default_algorithms::reverse (container &c) + { + std::reverse (begin(c), end(c)); + } + + ///////////////////////////////////////////////////////////////////////// + // Sort the contents of a container (std algorithm version) + ///////////////////////////////////////////////////////////////////////// + + template + void default_algorithms::sort (container &c) + { + std::sort (begin(c), end(c)); + } + + ///////////////////////////////////////////////////////////////////////// + // Special cases for std::list + ///////////////////////////////////////////////////////////////////////// + + template + struct list_algorithms : public default_algorithms + { + private: + typedef default_algorithms 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 + void list_algorithms::reverse (container &c) + { + c.reverse(); + } + + ///////////////////////////////////////////////////////////////////////// + // Sort the contents of a container (std algorithm version) + ///////////////////////////////////////////////////////////////////////// + + template + void list_algorithms::sort (container &c) + { + c.sort(); + } + + ///////////////////////////////////////////////////////////////////////// + // Special cases for associative containers + ///////////////////////////////////////////////////////////////////////// + + template + struct assoc_algorithms : public default_algorithms + { + private: + typedef default_algorithms Parent; + + public: + typedef typename Parent::iterator iterator; + typedef typename Parent::size_type size_type; + typedef typename Parent::container container; + typedef typename Parent::reference reference; + typedef typename Parent::key_param key_param; + typedef typename Parent::index_param index_param; + typedef typename Parent::value_param value_param; + + static reference get (container &, index_param); + static void assign (container &, index_param, value_param); + + // Use member functions for the following (hiding base class versions) + static iterator find (container &, key_param); + static size_type count (container &, key_param); + }; + + ///////////////////////////////////////////////////////////////////////// + // Index into a container (associative version) + ///////////////////////////////////////////////////////////////////////// + + template + typename assoc_algorithms::reference + assoc_algorithms::get (container &c, index_param ix) + { + iterator iter = find (c, ix); + + if (iter == end(c)) + { + throw std::domain_error + (std::string ("associative container: key not found")); + } + + else + { + return iter->second; + } + } + + ///////////////////////////////////////////////////////////////////////// + // Assign a value at a particular index (associative version) + ///////////////////////////////////////////////////////////////////////// + + template + void + assoc_algorithms::assign (container &c + , index_param ix + , value_param val) + { + c[ix] = val; + } + + ///////////////////////////////////////////////////////////////////////// + // Find an element in an associative container + ///////////////////////////////////////////////////////////////////////// + + template + typename assoc_algorithms::iterator + assoc_algorithms::find (container &c, key_param key) + { + return c.find (key); + } + + ///////////////////////////////////////////////////////////////////////// + // Count occurances of an element in a container (associative version) + ///////////////////////////////////////////////////////////////////////// + + template + typename assoc_algorithms::size_type + assoc_algorithms::count (container &c, key_param key) + { + return c.count (key); + } +} + +#endif // algorithms_rmg_20030823_included From 33e3f4b6c98146c3e6bfbcd6cf89d6d4b155e3ee Mon Sep 17 00:00:00 2001 From: Raoul Gough Date: Thu, 11 Sep 2003 22:34:10 +0000 Subject: [PATCH 24/39] def_visitor to add indexing capabilities to a Boost Python class [SVN r1533] --- .../boost/python/suite/indexing/visitor.hpp | 160 ++++++++++++++++++ 1 file changed, 160 insertions(+) create mode 100755 include/boost/python/suite/indexing/visitor.hpp diff --git a/include/boost/python/suite/indexing/visitor.hpp b/include/boost/python/suite/indexing/visitor.hpp new file mode 100755 index 00000000..d759cecd --- /dev/null +++ b/include/boost/python/suite/indexing/visitor.hpp @@ -0,0 +1,160 @@ +// -*- mode:c++ -*- +// +// Header file visitor.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/ 9/11 rmg File creation from container_suite.hpp +// +// $Id$ +// + +#ifndef visitor_rmg_20030823_included +#define visitor_rmg_20030823_included + +#include "slice_handler.hpp" + +#include +#include + +namespace indexing { + template + struct maybe_add_getitem { + template + static void apply (PythonClass &, Algorithms const &, Policy const &) { } + }; + + template<> + struct maybe_add_getitem { + template + static void apply (PythonClass &pyClass + , Algorithms const & + , Policy const &policy) + { + pyClass.def ("__getitem__", &Algorithms::get, policy); + } + }; + + template<> + struct maybe_add_getitem { + template + static void apply (PythonClass &pyClass + , Algorithms const & + , Policy const &policy) + { + pyClass.def ("__getitem__", &Algorithms::get, policy); + pyClass.def ("__getitem__" + , slice_handler::make_getitem (policy)); + } + }; + + template + struct maybe_add_setitem { + template + static void apply (PythonClass &, Algorithms const &, Policy const &) { } + }; + + template<> + struct maybe_add_setitem { + template + static void apply (PythonClass &pyClass + , Algorithms const & + , Policy const &policy) + { + pyClass.def ("__setitem__", &Algorithms::assign, policy); + } + }; + + template<> + struct maybe_add_setitem { + template + static void apply (PythonClass &pyClass + , Algorithms const & + , Policy const &policy) + { + pyClass.def ("__setitem__", &Algorithms::assign, policy); + pyClass.def ("__setitem__" + , slice_handler::make_setitem (policy)); + } + }; + + template + struct maybe_add_iter { + template + static void apply (PythonClass &, Algorithms const &, Policy const &) { } + }; + + template<> + struct maybe_add_iter { + template + static void apply (PythonClass &pyClass + , Algorithms const & + , Policy const &policy) + { + pyClass.def ("__iter__" + , boost::python::range (Algorithms::begin + , Algorithms::end)); + } + }; + + template + struct maybe_add_append { + template + static void apply (PythonClass &, Algorithms const &, Policy const &) { } + }; + + template<> + struct maybe_add_append { + template + static void apply (PythonClass &pyClass + , Algorithms const & + , Policy const &policy) + { + pyClass.def ("append", &Algorithms::push_back, policy); + } + }; + + template + class visitor + : public boost::python::def_visitor< visitor< Algorithms, Policy > > + { + Policy mPolicy; + + public: + typedef Algorithms algorithms; + typedef typename algorithms::container_traits traits; + + visitor (Policy const &policy) : mPolicy (policy) { } + + template + void visit (PythonClass &pyClass) const + { + maybe_add_getitem + ::apply (pyClass, algorithms(), mPolicy); + + maybe_add_setitem + ::apply (pyClass, algorithms(), mPolicy); + + maybe_add_iter<((traits::index_style != index_style_linear) + && traits::has_copyable_iter)> + ::apply (pyClass, algorithms(), mPolicy); + + maybe_add_append + ::apply (pyClass, algorithms(), mPolicy); + } + }; +} + +#endif // visitor_rmg_20030823_included From acfc856f6e67ca411f8bd7db4519165a23edf60d Mon Sep 17 00:00:00 2001 From: Raoul Gough Date: Thu, 11 Sep 2003 22:35:32 +0000 Subject: [PATCH 25/39] Automatic selection of algorithms by container type (uses partial specializations) [SVN r1534] --- .../python/suite/indexing/algo_selector.hpp | 186 ++++++++++++++++++ 1 file changed, 186 insertions(+) create mode 100755 include/boost/python/suite/indexing/algo_selector.hpp diff --git a/include/boost/python/suite/indexing/algo_selector.hpp b/include/boost/python/suite/indexing/algo_selector.hpp new file mode 100755 index 00000000..5244fc77 --- /dev/null +++ b/include/boost/python/suite/indexing/algo_selector.hpp @@ -0,0 +1,186 @@ +// -*- mode:c++ -*- +// +// Header file algo_selector.hpp +// +// Automatic selection of container algorithms (and traits) for known +// container types (basically, all STL container instances, as well as +// iterator_pair instances). +// +// 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/ 9/11 rmg File creation +// +// $Id$ +// + +#ifndef algo_selector_rmg_20030911_included +#define algo_selector_rmg_20030911_included + +#include "container_traits.hpp" +#include "algorithms.hpp" + +// Definitions of supported types +#include "iterator_pair.hpp" +#include +#include +#include +#include +#include + +namespace indexing { + ///////////////////////////////////////////////////////////////////////// + // Automated algorithm and trait selection + ///////////////////////////////////////////////////////////////////////// + + namespace detail { + template struct selector_impl; + + // selector_impl instances should include *two* publically + // accessible typedefs, one for the non-const version of the + // container, and one for the const version. This saves having to + // have two specializations of selector_impl for every kind of + // container. + + // std::set + template + class selector_impl > + { + typedef std::set Container; + + typedef set_traits mutable_traits; + typedef set_traits const_traits; + + public: + typedef assoc_algorithms mutable_algorithms; + typedef assoc_algorithms const_algorithms; + }; + + // std::multiset + template + class selector_impl > + { + typedef std::multiset Container; + + typedef set_traits mutable_traits; + typedef set_traits const_traits; + + public: + typedef assoc_algorithms mutable_algorithms; + typedef assoc_algorithms const_algorithms; + }; + + // std::map + template + class selector_impl > + { + typedef std::map Container; + + typedef map_traits mutable_traits; + typedef map_traits const_traits; + + public: + typedef assoc_algorithms mutable_algorithms; + typedef assoc_algorithms const_algorithms; + }; + + // std::multimap + template + class selector_impl > + { + typedef std::multimap Container; + + typedef map_traits mutable_traits; + typedef map_traits const_traits; + + public: + typedef assoc_algorithms mutable_algorithms; + typedef assoc_algorithms const_algorithms; + }; + + // std::vector + template + class selector_impl > + { + typedef std::vector Container; + + typedef default_sequence_traits mutable_traits; + typedef default_sequence_traits const_traits; + + public: + typedef default_algorithms mutable_algorithms; + typedef default_algorithms const_algorithms; + }; + + // std::deque + template + class selector_impl > + { + typedef std::deque Container; + + typedef default_sequence_traits mutable_traits; + typedef default_sequence_traits const_traits; + + public: + typedef default_algorithms mutable_algorithms; + typedef default_algorithms const_algorithms; + }; + + // std::list + template + class selector_impl > + { + typedef std::list Container; + + typedef default_sequence_traits mutable_traits; + typedef default_sequence_traits const_traits; + + public: + typedef list_algorithms mutable_algorithms; + typedef list_algorithms const_algorithms; + }; + + // Iterator ranges + template + class selector_impl > + { + typedef ::indexing::iterator_pair Container; + + typedef iterator_pair_traits mutable_traits; + typedef iterator_pair_traits const_traits; // ? + + public: + typedef default_algorithms mutable_algorithms; + typedef default_algorithms const_algorithms; + }; + } + + // Select the right algorithms for each supported kind of container + + // Generic version (mutable containers) + template + struct algo_selector + : public detail::selector_impl::mutable_algorithms + { + }; + + // Partial specialization for const containers + template + struct algo_selector + : public detail::selector_impl::const_algorithms + { + }; +} + +#endif // algo_selector_rmg_20030911_included From 555c99156d53196e9bc332c3e49c5a41698d5709 Mon Sep 17 00:00:00 2001 From: Raoul Gough Date: Thu, 11 Sep 2003 22:36:18 +0000 Subject: [PATCH 26/39] Split algorithms portion into seperate header algorithms.hpp [SVN r1535] --- .../python/suite/indexing/suite_utils.hpp | 249 +----------------- 1 file changed, 2 insertions(+), 247 deletions(-) diff --git a/include/boost/python/suite/indexing/suite_utils.hpp b/include/boost/python/suite/indexing/suite_utils.hpp index 4b05b9da..a44eeb7b 100755 --- a/include/boost/python/suite/indexing/suite_utils.hpp +++ b/include/boost/python/suite/indexing/suite_utils.hpp @@ -2,6 +2,8 @@ // // Header file suite_utils.hpp // +// Shared utilities for the indexing suite. +// // Copyright (c) 2003 Raoul M. Gough // // This material is provided "as is", with absolutely no warranty expressed @@ -25,10 +27,6 @@ #define suite_utils_rmg_20030823_included #include -#include -#include -#include -#include namespace indexing { template @@ -39,249 +37,6 @@ namespace indexing { public: static bool const value = ! boost::is_const::value; }; - - template - struct container_algorithms - { - typedef typename ContainerTraits::container container; - typedef typename ContainerTraits::iterator iterator; - typedef typename ContainerTraits::reference reference; - typedef typename ContainerTraits::key_type key_type; - typedef typename ContainerTraits::size_type size_type; - typedef typename ContainerTraits::index_type index_type; - typedef typename ContainerTraits::value_type value_type; - - typedef typename boost::call_traits::param_type value_param; - typedef typename boost::call_traits::param_type key_param; - typedef typename boost::call_traits::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 reference get (container &, index_param); - static void assign (container &, index_param, value_param); - static void push_back (container &, value_param); - static void sort (container &); - // static void sort (container &, PyObject *); - - static iterator begin (container &c) { return c.begin(); } - static iterator end (container &c) { return c.end(); } - }; - - ///////////////////////////////////////////////////////////////////////// - // Get the size of a container - ///////////////////////////////////////////////////////////////////////// - - template - typename container_algorithms::size_type - container_algorithms::size (container &c) - { - return c.size(); - } - - ///////////////////////////////////////////////////////////////////////// - // Find an element in a container (std algorithm version) - ///////////////////////////////////////////////////////////////////////// - - template - typename container_algorithms::iterator - container_algorithms::find (container &c - , key_param key) - { - return std::find (begin(c), end(c), key); - } - - ///////////////////////////////////////////////////////////////////////// - // Count occurances of an element in a container (std algorithm version) - ///////////////////////////////////////////////////////////////////////// - - template - typename container_algorithms::size_type - container_algorithms::count (container &c - , key_param key) - { - return std::count (begin(c), end(c), key); - } - - ///////////////////////////////////////////////////////////////////////// - // Index into a container (generic version) - ///////////////////////////////////////////////////////////////////////// - - template - typename container_algorithms::reference - container_algorithms::get (container &c, index_param ix) - { - return c.at (ix); - } - - ///////////////////////////////////////////////////////////////////////// - // Assign a value at a particular index (generic version) - ///////////////////////////////////////////////////////////////////////// - - template - void - container_algorithms::assign (container &c - , index_param ix - , value_param val) - { - c.at(ix) = val; - } - - ///////////////////////////////////////////////////////////////////////// - // Insert at end of a container (generic version) - ///////////////////////////////////////////////////////////////////////// - - template - void - container_algorithms::push_back (container &c - , value_param v) - { - c.push_back (v); - } - - ///////////////////////////////////////////////////////////////////////// - // Reverse the contents of a container (std algorithm version) - ///////////////////////////////////////////////////////////////////////// - - template - void container_algorithms::reverse (container &c) - { - std::reverse (begin(c), end(c)); - } - - ///////////////////////////////////////////////////////////////////////// - // Sort the contents of a container (std algorithm version) - ///////////////////////////////////////////////////////////////////////// - - template - void container_algorithms::sort (container &c) - { - std::sort (begin(c), end(c)); - } - - ///////////////////////////////////////////////////////////////////////// - // Special cases for std::list - ///////////////////////////////////////////////////////////////////////// - - template - struct list_algorithms : public container_algorithms - { - private: - typedef container_algorithms 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 - void list_algorithms::reverse (container &c) - { - c.reverse(); - } - - ///////////////////////////////////////////////////////////////////////// - // Sort the contents of a container (std algorithm version) - ///////////////////////////////////////////////////////////////////////// - - template - void list_algorithms::sort (container &c) - { - c.sort(); - } - - ///////////////////////////////////////////////////////////////////////// - // Special cases for associative containers - ///////////////////////////////////////////////////////////////////////// - - template - struct assoc_algorithms : public container_algorithms - { - private: - typedef container_algorithms Parent; - - public: - typedef typename Parent::iterator iterator; - typedef typename Parent::size_type size_type; - typedef typename Parent::container container; - typedef typename Parent::reference reference; - typedef typename Parent::key_param key_param; - typedef typename Parent::index_param index_param; - typedef typename Parent::value_param value_param; - - static reference get (container &, index_param); - static void assign (container &, index_param, value_param); - - // Use member functions for the following (hiding base class versions) - static iterator find (container &, key_param); - static size_type count (container &, key_param); - }; - - ///////////////////////////////////////////////////////////////////////// - // Index into a container (associative version) - ///////////////////////////////////////////////////////////////////////// - - template - typename assoc_algorithms::reference - assoc_algorithms::get (container &c, index_param ix) - { - iterator iter = find (c, ix); - - if (iter == end(c)) - { - throw std::domain_error - (std::string ("associative container: key not found")); - } - - else - { - return iter->second; - } - } - - ///////////////////////////////////////////////////////////////////////// - // Assign a value at a particular index (associative version) - ///////////////////////////////////////////////////////////////////////// - - template - void - assoc_algorithms::assign (container &c - , index_param ix - , value_param val) - { - c[ix] = val; - } - - ///////////////////////////////////////////////////////////////////////// - // Find an element in an associative container - ///////////////////////////////////////////////////////////////////////// - - template - typename assoc_algorithms::iterator - assoc_algorithms::find (container &c, key_param key) - { - return c.find (key); - } - - ///////////////////////////////////////////////////////////////////////// - // Count occurances of an element in a container (associative version) - ///////////////////////////////////////////////////////////////////////// - - template - typename assoc_algorithms::size_type - assoc_algorithms::count (container &c, key_param key) - { - return c.count (key); - } } #endif // suite_utils_rmg_20030823_included From 4e41dbba6f9cd611132a544abb2d2c7099eb6af1 Mon Sep 17 00:00:00 2001 From: Raoul Gough Date: Thu, 11 Sep 2003 22:37:53 +0000 Subject: [PATCH 27/39] Explicitly include boost/type_traits [SVN r1536] --- include/boost/python/suite/indexing/iterator_pair.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/include/boost/python/suite/indexing/iterator_pair.hpp b/include/boost/python/suite/indexing/iterator_pair.hpp index e86e427b..f4a37e89 100755 --- a/include/boost/python/suite/indexing/iterator_pair.hpp +++ b/include/boost/python/suite/indexing/iterator_pair.hpp @@ -30,6 +30,7 @@ #include #include #include +#include namespace indexing { template From ec103b76cde8ba57c224204fee96925a75c121a3 Mon Sep 17 00:00:00 2001 From: Raoul Gough Date: Thu, 11 Sep 2003 22:38:39 +0000 Subject: [PATCH 28/39] Remove algorithms typedefs (which were kind of circular in nature) [SVN r1537] --- .../suite/indexing/container_traits.hpp | 143 ------------------ 1 file changed, 143 deletions(-) diff --git a/include/boost/python/suite/indexing/container_traits.hpp b/include/boost/python/suite/indexing/container_traits.hpp index 04b4abff..5c121d96 100755 --- a/include/boost/python/suite/indexing/container_traits.hpp +++ b/include/boost/python/suite/indexing/container_traits.hpp @@ -29,13 +29,6 @@ #include "iterator_suite.hpp" #include -#include "iterator_pair.hpp" -#include -#include -#include -#include -#include - namespace indexing { ///////////////////////////////////////////////////////////////////////// // Traits for the iterator_pair container emulator @@ -54,9 +47,6 @@ namespace indexing { 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 algorithms; }; ///////////////////////////////////////////////////////////////////////// @@ -105,9 +95,6 @@ namespace indexing { 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 algorithms; }; ///////////////////////////////////////////////////////////////////////// @@ -121,13 +108,6 @@ namespace indexing { static bool const has_push_back = is_mutable; }; - template - struct list_traits : public default_sequence_traits - { - // Some special algo's for list (using member functions) - typedef list_algorithms algorithms; - }; - ///////////////////////////////////////////////////////////////////////// // Associative containers set and multiset ///////////////////////////////////////////////////////////////////////// @@ -136,9 +116,6 @@ namespace indexing { struct set_traits : public default_container_traits { static IndexStyle const index_style = index_style_nonlinear; - - // Special algo's for set types (using member functions) - typedef assoc_algorithms algorithms; }; ///////////////////////////////////////////////////////////////////////// @@ -155,126 +132,6 @@ namespace indexing { typedef typename Container::key_type key_type; // find, count, ... static IndexStyle const index_style = index_style_nonlinear; - - // Special algo's for map types (using member functions) - typedef assoc_algorithms algorithms; - }; - - ///////////////////////////////////////////////////////////////////////// - // Automated trait selection - ///////////////////////////////////////////////////////////////////////// - - namespace container_details { - template 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 traits_by_type > - { - typedef std::set Container; - - public: - typedef set_traits mutable_type; - typedef set_traits const_type; - }; - - // std::multiset - template - class traits_by_type > - { - typedef std::multiset Container; - - public: - typedef set_traits mutable_type; - typedef set_traits const_type; - }; - - // std::map - template - class traits_by_type > - { - typedef std::map Container; - - public: - typedef map_traits mutable_type; - typedef map_traits const_type; - }; - - // std::multimap - template - class traits_by_type > - { - typedef std::multimap Container; - - public: - typedef map_traits mutable_type; - typedef map_traits const_type; - }; - - // std::vector - template - class traits_by_type > - { - typedef std::vector Container; - - public: - typedef default_sequence_traits mutable_type; - typedef default_sequence_traits const_type; - }; - - // std::deque - template - class traits_by_type > - { - typedef std::deque Container; - - public: - typedef default_sequence_traits mutable_type; - typedef default_sequence_traits const_type; - }; - - // std::list - template - class traits_by_type > - { - typedef std::list Container; - - public: - typedef list_traits mutable_type; - typedef list_traits const_type; - }; - - // Iterator ranges - template - class traits_by_type > - { - typedef ::indexing::iterator_pair Container; - - public: - typedef iterator_pair_traits mutable_type; - typedef iterator_pair_traits const_type; // ? - }; - } - - // Select the right traits for each supported kind of container - - // Generic version (mutable containers) - template - struct container_traits - : public container_details::traits_by_type::mutable_type - { - }; - - // Partial specialization for const containers - template - struct container_traits - : public container_details::traits_by_type::const_type - { }; } From 0cf6fdc7f040b55491b0e4232dfbb40238ed8465 Mon Sep 17 00:00:00 2001 From: Raoul Gough Date: Thu, 11 Sep 2003 22:39:54 +0000 Subject: [PATCH 29/39] Seperate most code into visitor.hpp, use algo_selector instead of container_traits [SVN r1538] --- .../python/suite/indexing/container_suite.hpp | 149 +----------------- 1 file changed, 7 insertions(+), 142 deletions(-) diff --git a/include/boost/python/suite/indexing/container_suite.hpp b/include/boost/python/suite/indexing/container_suite.hpp index 517692a2..c8a301a2 100755 --- a/include/boost/python/suite/indexing/container_suite.hpp +++ b/include/boost/python/suite/indexing/container_suite.hpp @@ -25,163 +25,28 @@ #ifndef container_suite_rmg_20030823_included #define container_suite_rmg_20030823_included -#include "container_traits.hpp" -#include "slice_handler.hpp" +#include "algo_selector.hpp" +#include "visitor.hpp" #include #include -#include -#include - -// #include namespace indexing { - template - struct maybe_add_getitem { - template - static void apply (PythonClass &, Algorithms const &, Policy const &) { } - }; - - template<> - struct maybe_add_getitem { - template - static void apply (PythonClass &pyClass - , Algorithms const & - , Policy const &policy) - { - pyClass.def ("__getitem__", &Algorithms::get, policy); - } - }; - - template<> - struct maybe_add_getitem { - template - static void apply (PythonClass &pyClass - , Algorithms const & - , Policy const &policy) - { - pyClass.def ("__getitem__", &Algorithms::get, policy); - pyClass.def ("__getitem__" - , slice_handler::make_getitem (policy)); - } - }; - - template - struct maybe_add_setitem { - template - static void apply (PythonClass &, Algorithms const &, Policy const &) { } - }; - - template<> - struct maybe_add_setitem { - template - static void apply (PythonClass &pyClass - , Algorithms const & - , Policy const &policy) - { - pyClass.def ("__setitem__", &Algorithms::assign, policy); - } - }; - - template<> - struct maybe_add_setitem { - template - static void apply (PythonClass &pyClass - , Algorithms const & - , Policy const &policy) - { - pyClass.def ("__setitem__", &Algorithms::assign, policy); - pyClass.def ("__setitem__" - , slice_handler::make_setitem (policy)); - } - }; - - template - struct maybe_add_iter { - template - static void apply (PythonClass &, Algorithms const &, Policy const &) { } - }; - - template<> - struct maybe_add_iter { - template - static void apply (PythonClass &pyClass - , Algorithms const & - , Policy const &policy) - { - pyClass.def ("__iter__" - , boost::python::range (Algorithms::begin - , Algorithms::end)); - } - }; - - template - struct maybe_add_append { - template - static void apply (PythonClass &, Algorithms const &, Policy const &) { } - }; - - template<> - struct maybe_add_append { - template - static void apply (PythonClass &pyClass - , Algorithms const & - , Policy const &policy) - { - pyClass.def ("append", &Algorithms::push_back, policy); - } - }; - - template - class container_suite_impl - : public boost::python::def_visitor > - { - Policy mPolicy; - - public: - typedef typename Traits::algorithms algorithms; - typedef typename Traits::reference reference_return; - typedef Policy return_policy; - - container_suite_impl (Policy const &policy) : mPolicy (policy) { } - - template - void visit (PythonClass &pyClass) const - { - maybe_add_getitem - ::apply (pyClass, algorithms(), mPolicy); - - maybe_add_setitem - ::apply (pyClass, algorithms(), mPolicy); - - maybe_add_iter<((Traits::index_style != index_style_linear) - && Traits::has_copyable_iter)> - ::apply (pyClass, algorithms(), mPolicy); - - maybe_add_append - ::apply (pyClass, algorithms(), mPolicy); - } - }; - - template > + template > struct container_suite { typedef boost::python::return_value_policy default_policies; - static - container_suite_impl - generate () + static visitor generate () { - return container_suite_impl (default_policies()); + return visitor (default_policies()); } template - static - container_suite_impl - generate (Policy const &policy) + static visitor generate (Policy const &policy) { - return container_suite_impl (policy); + return visitor (policy); } }; } From b59e147b3b2210d12d2c92077327a2f63adbb1a4 Mon Sep 17 00:00:00 2001 From: Raoul Gough Date: Thu, 18 Sep 2003 17:33:33 +0000 Subject: [PATCH 30/39] Renaming iterator_suite.hpp to more appropriate iterator_traits.hpp [SVN r1560] --- .../python/suite/indexing/iterator_suite.hpp | 149 ------------------ 1 file changed, 149 deletions(-) delete mode 100755 include/boost/python/suite/indexing/iterator_suite.hpp diff --git a/include/boost/python/suite/indexing/iterator_suite.hpp b/include/boost/python/suite/indexing/iterator_suite.hpp deleted file mode 100755 index ed6bffbb..00000000 --- a/include/boost/python/suite/indexing/iterator_suite.hpp +++ /dev/null @@ -1,149 +0,0 @@ -// -*- 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 -#include -#include - -namespace indexing { - enum IndexStyle { - index_style_none // No random access (iteration only) - , index_style_nonlinear // Random access by key (no slicing) - , index_style_linear // Random access by integer index (allows slicing) - }; - - ////////////////////////////////////////////////////////////////////////// - // Indexing traits for containers based on iterator pairs - ////////////////////////////////////////////////////////////////////////// - - template - struct input_iterator_traits - { - private: - typedef std::iterator_traits 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_mutable_ref = is_mutable_ref::value; - static IndexStyle const index_style = index_style_none; - }; - - template - struct forward_iterator_traits - : public input_iterator_traits - { - static bool const has_copyable_iter = true; - }; - - template - struct bidirectional_iterator_traits - : public forward_iterator_traits - { - static bool const is_reversible = has_mutable_ref; - }; - - template - struct random_access_iterator_traits - : public bidirectional_iterator_traits - { - static IndexStyle const index_style = index_style_linear; - }; - - 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 struct traits_by_size { }; - - template<> - struct traits_by_size { - template - struct traits { - typedef input_iterator_traits type; - }; - }; - - template<> - struct traits_by_size { - template - struct traits { - typedef forward_iterator_traits type; - }; - }; - - template<> - struct traits_by_size { - template - struct traits { - typedef bidirectional_iterator_traits type; - }; - }; - - template<> - struct traits_by_size { - template - struct traits { - typedef random_access_iterator_traits type; - }; - }; - - template - class traits_by_category { - typedef typename std::iterator_traits::iterator_category - iterator_category; - - static size_t const size = sizeof(sizer(iterator_category())); - - public: - typedef typename traits_by_size::traits::type type; - }; - } - - template - struct iterator_traits - : public iterator_detail::traits_by_category::type - { - }; -} - -#endif // iterator_suite_rmg_20030823_included From 5f54f7f82be62e9774bf58dec2160954acbffdd9 Mon Sep 17 00:00:00 2001 From: Raoul Gough Date: Thu, 18 Sep 2003 17:34:35 +0000 Subject: [PATCH 31/39] Extended iterator traits for the indexing suite (formerly iterator_suite.hpp) [SVN r1561] --- .../python/suite/indexing/iterator_traits.hpp | 154 ++++++++++++++++++ 1 file changed, 154 insertions(+) create mode 100755 include/boost/python/suite/indexing/iterator_traits.hpp diff --git a/include/boost/python/suite/indexing/iterator_traits.hpp b/include/boost/python/suite/indexing/iterator_traits.hpp new file mode 100755 index 00000000..a7103362 --- /dev/null +++ b/include/boost/python/suite/indexing/iterator_traits.hpp @@ -0,0 +1,154 @@ +// -*- mode:c++ -*- +// +// Header file iterator_traits.hpp +// +// Traits information about iterators for use in determining what +// Python methods to support for a 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/23 rmg File creation as iterator_suite.hpp +// 2003/ 9/12 rmg Renamed iterator_traits.hpp +// +// $Id$ +// + +#ifndef iterator_traits_rmg_20030823_included +#define iterator_traits_rmg_20030823_included + +#include "suite_utils.hpp" + +#include +#include +#include + +namespace indexing { + enum IndexStyle { + index_style_none // No random access (iteration only) + , index_style_nonlinear // Random access by key (no slicing) + , index_style_linear // Random access by integer index (allows slicing) + }; + + ////////////////////////////////////////////////////////////////////////// + // Indexing traits for containers based on iterator pairs + ////////////////////////////////////////////////////////////////////////// + + template + struct input_iterator_traits + { + private: + typedef std::iterator_traits 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; + + BOOST_STATIC_CONSTANT (bool, has_copyable_iter = false); + BOOST_STATIC_CONSTANT (bool, is_reversible = false); + BOOST_STATIC_CONSTANT (bool, has_mutable_ref + = is_mutable_ref::value); + + BOOST_STATIC_CONSTANT (IndexStyle, index_style = index_style_none); + }; + + template + struct forward_iterator_traits + : public input_iterator_traits + { + BOOST_STATIC_CONSTANT (bool, has_copyable_iter = true); + }; + + template + struct bidirectional_iterator_traits + : public forward_iterator_traits + { + BOOST_STATIC_CONSTANT (bool, is_reversible = has_mutable_ref); + }; + + template + struct random_access_iterator_traits + : public bidirectional_iterator_traits + { + BOOST_STATIC_CONSTANT (IndexStyle, index_style = index_style_linear); + }; + + 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 struct traits_by_size { }; + + template<> + struct traits_by_size { + template + struct traits { + typedef input_iterator_traits type; + }; + }; + + template<> + struct traits_by_size { + template + struct traits { + typedef forward_iterator_traits type; + }; + }; + + template<> + struct traits_by_size { + template + struct traits { + typedef bidirectional_iterator_traits type; + }; + }; + + template<> + struct traits_by_size { + template + struct traits { + typedef random_access_iterator_traits type; + }; + }; + + template + class traits_by_category { + typedef typename std::iterator_traits::iterator_category + iterator_category; + + BOOST_STATIC_CONSTANT (size_t, size + = sizeof(sizer(iterator_category()))); + + public: + typedef typename traits_by_size::traits::type type; + }; + } + + template + struct iterator_traits + : public iterator_detail::traits_by_category::type + { + }; +} + +#endif // iterator_traits_rmg_20030823_included From bb376514b19f83616a65b01bd6a871a623b4ba6d Mon Sep 17 00:00:00 2001 From: Raoul Gough Date: Thu, 18 Sep 2003 17:36:03 +0000 Subject: [PATCH 32/39] Proxy object for an element in a container_proxy [SVN r1562] --- .../python/suite/indexing/element_proxy.hpp | 195 ++++++++++++++++++ 1 file changed, 195 insertions(+) create mode 100755 include/boost/python/suite/indexing/element_proxy.hpp diff --git a/include/boost/python/suite/indexing/element_proxy.hpp b/include/boost/python/suite/indexing/element_proxy.hpp new file mode 100755 index 00000000..705abef8 --- /dev/null +++ b/include/boost/python/suite/indexing/element_proxy.hpp @@ -0,0 +1,195 @@ +// -*- mode:c++ -*- +// +// Header file element_proxy.hpp +// +// Proxy objects for invidivual elements in a container wrapped by +// container_proxy +// +// 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/ 9/15 rmg File creation from container_proxy.hpp +// +// $Id$ +// + +#ifndef element_proxy_rmg_20030915_included +#define element_proxy_rmg_20030915_included + +#include "shared_proxy_impl.hpp" +#include + +#include "value_traits.hpp" +#include +#include +#include + +template +class element_proxy +{ + template friend struct const_element_proxy; + + typedef ContainerProxy container_proxy; + typedef typename container_proxy::shared_proxy proxy_type; + typedef boost::shared_ptr proxy_pointer; + typedef typename container_proxy::raw_value_type raw_value_type; + typedef typename container_proxy::size_type size_type; + + 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 ©) + { + 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 ©) + { + // 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 +}; + +template +struct const_element_proxy +{ + typedef ContainerProxy container_proxy; + typedef typename container_proxy::shared_proxy proxy_type; + typedef boost::shared_ptr proxy_pointer; + typedef typename container_proxy::raw_value_type raw_value_type; + + 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 ©) + : 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 +}; + +namespace boost +{ + template + typename ContainerProxy::raw_value_type * + get_pointer (element_proxy const &proxy) + { + return &(*proxy); + } +} + +namespace indexing { + template + struct value_traits > + : public value_traits + { + template + static void visitor_helper (PythonClass &, Policy const &) + { + typedef element_proxy element_proxy_; + typedef typename ContainerProxy::raw_value_type raw_value_type; + + boost::python::register_ptr_to_python(); + boost::python::implicitly_convertible(); + } + }; +} + +#endif // element_proxy_rmg_20030915_included From 59a243f43408d648a45300c46c3e60241d80274f Mon Sep 17 00:00:00 2001 From: Raoul Gough Date: Thu, 18 Sep 2003 17:36:56 +0000 Subject: [PATCH 33/39] Extended traits for values stored in containers to be exposed by the indexing suite [SVN r1563] --- .../python/suite/indexing/value_traits.hpp | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100755 include/boost/python/suite/indexing/value_traits.hpp diff --git a/include/boost/python/suite/indexing/value_traits.hpp b/include/boost/python/suite/indexing/value_traits.hpp new file mode 100755 index 00000000..14f91bda --- /dev/null +++ b/include/boost/python/suite/indexing/value_traits.hpp @@ -0,0 +1,45 @@ +// -*- mode:c++ -*- +// +// Header file value_traits.hpp +// +// Traits information about container element types for use in +// determining which Python methods to support for a 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/ 9/12 rmg File creation +// +// $Id$ +// + +#ifndef value_traits_rmg_20030912_included +#define value_traits_rmg_20030912_included + +namespace indexing { + template + struct value_traits { + static bool const equality_comparable = true; + // Meaning from C++98 standard section 20.1.1 + + // static bool const has_less = true; + // etc... + + // Default, do-nothing, version of visitor_helper + template + static void visitor_helper (PythonClass &, Policy const &) { } + }; +} + +#endif // value_traits_rmg_20030912_included From 752542b4b3298ec760eed58bd9439220bce7538b Mon Sep 17 00:00:00 2001 From: Raoul Gough Date: Thu, 18 Sep 2003 17:45:39 +0000 Subject: [PATCH 34/39] Synchronize with local work [SVN r1564] --- .../python/suite/indexing/IntWrapper.cpp | 18 + .../python/suite/indexing/IntWrapper.hpp | 1 + .../python/suite/indexing/algo_selector.hpp | 15 + .../python/suite/indexing/algorithms.hpp | 476 +++++++++++------- .../python/suite/indexing/container_proxy.hpp | 154 +----- .../python/suite/indexing/container_suite.hpp | 4 +- .../suite/indexing/container_traits.hpp | 151 +++--- .../boost/python/suite/indexing/indexing.cpp | 56 ++- include/boost/python/suite/indexing/slice.cpp | 22 - include/boost/python/suite/indexing/slice.hpp | 23 +- .../python/suite/indexing/slice_handler.hpp | 107 +++- .../boost/python/suite/indexing/testarray.py | 35 +- .../python/suite/indexing/testindexing.py | 69 ++- .../boost/python/suite/indexing/testsuite.cpp | 9 +- .../boost/python/suite/indexing/testvector.py | 60 ++- .../indexing/vector_indexing_suite_ext.cpp | 14 +- .../boost/python/suite/indexing/visitor.hpp | 310 +++++++++++- 17 files changed, 1056 insertions(+), 468 deletions(-) diff --git a/include/boost/python/suite/indexing/IntWrapper.cpp b/include/boost/python/suite/indexing/IntWrapper.cpp index f5c6dc04..2830db91 100755 --- a/include/boost/python/suite/indexing/IntWrapper.cpp +++ b/include/boost/python/suite/indexing/IntWrapper.cpp @@ -121,6 +121,24 @@ bool operator< (IntWrapper const &lhs, IntWrapper const &rhs) return lhs.mI < rhs.mI; } +int compare (IntWrapper const &lhs, IntWrapper const &rhs) +{ + if (lhs < rhs) + { + return -1; + } + + else if (rhs < lhs) + { + return 1; + } + + else + { + return 0; + } +} + std::ostream &operator<< (std::ostream &strm, IntWrapper const &iw) { strm << iw.mI; diff --git a/include/boost/python/suite/indexing/IntWrapper.hpp b/include/boost/python/suite/indexing/IntWrapper.hpp index c992063f..70c37c30 100755 --- a/include/boost/python/suite/indexing/IntWrapper.hpp +++ b/include/boost/python/suite/indexing/IntWrapper.hpp @@ -48,6 +48,7 @@ struct IntWrapper { bool operator== (IntWrapper const &lhs, IntWrapper const &rhs); bool operator< (IntWrapper const &lhs, IntWrapper const &rhs); +int compare (IntWrapper const &lhs, IntWrapper const &rhs); std::ostream &operator<< (std::ostream &strm, IntWrapper const &iw); #endif // IntWrapper_rmg_20030910_included diff --git a/include/boost/python/suite/indexing/algo_selector.hpp b/include/boost/python/suite/indexing/algo_selector.hpp index 5244fc77..2693cf58 100755 --- a/include/boost/python/suite/indexing/algo_selector.hpp +++ b/include/boost/python/suite/indexing/algo_selector.hpp @@ -33,6 +33,7 @@ // Definitions of supported types #include "iterator_pair.hpp" +#include "container_proxy.hpp" #include #include #include @@ -164,6 +165,20 @@ namespace indexing { typedef default_algorithms mutable_algorithms; typedef default_algorithms const_algorithms; }; + + // Container proxies + template + class selector_impl > + { + typedef container_proxy Container; + + typedef container_proxy_traits mutable_traits; + typedef container_proxy_traits const_traits; + + public: + typedef default_algorithms mutable_algorithms; + typedef default_algorithms const_algorithms; + }; } // Select the right algorithms for each supported kind of container diff --git a/include/boost/python/suite/indexing/algorithms.hpp b/include/boost/python/suite/indexing/algorithms.hpp index 7c44582c..84073c50 100755 --- a/include/boost/python/suite/indexing/algorithms.hpp +++ b/include/boost/python/suite/indexing/algorithms.hpp @@ -31,6 +31,7 @@ #include #include #include +#include #include namespace indexing { @@ -44,8 +45,8 @@ namespace indexing { typedef typename ContainerTraits::reference reference; typedef typename ContainerTraits::key_type key_type; typedef typename ContainerTraits::size_type size_type; - typedef typename ContainerTraits::index_type index_type; typedef typename ContainerTraits::value_type value_type; + typedef long index_type; // Ignore container traits (need signed repr.) typedef typename boost::call_traits::param_type value_param; typedef typename boost::call_traits::param_type key_param; @@ -58,132 +59,26 @@ namespace indexing { static reference get (container &, index_param); static void assign (container &, index_param, value_param); static void insert (container &, index_param, value_param); - static void erase (container &, index_param, index_param); + static void erase_one (container &, index_param); + static void erase_range(container &, index_param, index_param); static void push_back (container &, value_param); static void sort (container &); // static void sort (container &, PyObject *); static iterator begin (container &c) { return c.begin(); } static iterator end (container &c) { return c.end(); } + + template + static void visitor_helper (PythonClass &, Policy const &); + + private: + static size_type bounds_check (container &, index_param, char const *msg + , bool one_past = false); + // Throws std::out_of_range if necessary. If one_past is set, then + // indexes up to container.size() *inclusive* are allowed. Otherwise + // returns a normalized index. }; - ///////////////////////////////////////////////////////////////////////// - // Get the size of a container - ///////////////////////////////////////////////////////////////////////// - - template - typename default_algorithms::size_type - default_algorithms::size (container &c) - { - return c.size(); - } - - ///////////////////////////////////////////////////////////////////////// - // Find an element in a container (std algorithm version) - ///////////////////////////////////////////////////////////////////////// - - template - typename default_algorithms::iterator - default_algorithms::find (container &c - , key_param key) - { - return std::find (begin(c), end(c), key); - } - - ///////////////////////////////////////////////////////////////////////// - // Count occurances of an element in a container (std algorithm version) - ///////////////////////////////////////////////////////////////////////// - - template - typename default_algorithms::size_type - default_algorithms::count (container &c - , key_param key) - { - return std::count (begin(c), end(c), key); - } - - ///////////////////////////////////////////////////////////////////////// - // Index into a container (generic version) - ///////////////////////////////////////////////////////////////////////// - - template - typename default_algorithms::reference - default_algorithms::get (container &c, index_param ix) - { - return c.at (ix); - } - - ///////////////////////////////////////////////////////////////////////// - // Assign a value at a particular index (generic version) - ///////////////////////////////////////////////////////////////////////// - - template - void - default_algorithms::assign (container &c - , index_param ix - , value_param val) - { - c.at(ix) = val; - } - - ///////////////////////////////////////////////////////////////////////// - // Insert at end of a container (generic version) - ///////////////////////////////////////////////////////////////////////// - - template - void - default_algorithms::push_back (container &c - , value_param v) - { - c.push_back (v); - } - - ///////////////////////////////////////////////////////////////////////// - // Insert at an index in the container (generic version) - ///////////////////////////////////////////////////////////////////////// - - template - void - default_algorithms::insert (container &c - , index_param i - , value_param v) - { - c.insert (c.begin() + i, v); - } - - ///////////////////////////////////////////////////////////////////////// - // Erase between given indexes in the container (generic version) - ///////////////////////////////////////////////////////////////////////// - - template - void - default_algorithms::erase (container &c - , index_param from - , index_param to) - { - c.erase (c.begin() + from, c.begin() + to); - } - - ///////////////////////////////////////////////////////////////////////// - // Reverse the contents of a container (std algorithm version) - ///////////////////////////////////////////////////////////////////////// - - template - void default_algorithms::reverse (container &c) - { - std::reverse (begin(c), end(c)); - } - - ///////////////////////////////////////////////////////////////////////// - // Sort the contents of a container (std algorithm version) - ///////////////////////////////////////////////////////////////////////// - - template - void default_algorithms::sort (container &c) - { - std::sort (begin(c), end(c)); - } - ///////////////////////////////////////////////////////////////////////// // Special cases for std::list ///////////////////////////////////////////////////////////////////////// @@ -203,26 +98,6 @@ namespace indexing { // static void sort (container &, PyObject *); }; - ///////////////////////////////////////////////////////////////////////// - // Reverse the contents of a list (member function version) - ///////////////////////////////////////////////////////////////////////// - - template - void list_algorithms::reverse (container &c) - { - c.reverse(); - } - - ///////////////////////////////////////////////////////////////////////// - // Sort the contents of a container (std algorithm version) - ///////////////////////////////////////////////////////////////////////// - - template - void list_algorithms::sort (container &c) - { - c.sort(); - } - ///////////////////////////////////////////////////////////////////////// // Special cases for associative containers ///////////////////////////////////////////////////////////////////////// @@ -239,73 +114,300 @@ namespace indexing { typedef typename Parent::container container; typedef typename Parent::reference reference; typedef typename Parent::key_param key_param; - typedef typename Parent::index_param index_param; typedef typename Parent::value_param value_param; + // Use the trait's index type information to support non-integer indexes + typedef typename ContainerTraits::index_type index_type; + typedef typename boost::call_traits::param_type index_param; + static reference get (container &, index_param); static void assign (container &, index_param, value_param); // Use member functions for the following (hiding base class versions) + static void erase_one (container &, key_param); static iterator find (container &, key_param); static size_type count (container &, key_param); }; +} - ///////////////////////////////////////////////////////////////////////// - // Index into a container (associative version) - ///////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////// +// Get the size of a container +///////////////////////////////////////////////////////////////////////// - template - typename assoc_algorithms::reference - assoc_algorithms::get (container &c, index_param ix) - { - iterator iter = find (c, ix); +template +typename indexing::default_algorithms::size_type +indexing::default_algorithms::size (container &c) +{ + return c.size(); +} - if (iter == end(c)) - { - throw std::domain_error - (std::string ("associative container: key not found")); - } +///////////////////////////////////////////////////////////////////////// +// Range check an index and throw out_of_range if necessary +///////////////////////////////////////////////////////////////////////// - else - { - return iter->second; - } - } +template +typename indexing::default_algorithms::size_type +indexing::default_algorithms::bounds_check (container &c + , index_param ix + , char const *msg + , bool one_past) +{ + size_type bound = size(c) + (one_past ? 1 : 0); + size_type result; - ///////////////////////////////////////////////////////////////////////// - // Assign a value at a particular index (associative version) - ///////////////////////////////////////////////////////////////////////// + if (ix < 0) + { + if (size_type(-ix) > bound) + { + throw std::out_of_range (msg); + } - template - void - assoc_algorithms::assign (container &c - , index_param ix - , value_param val) - { - c[ix] = val; - } + result = bound + ix; + } - ///////////////////////////////////////////////////////////////////////// - // Find an element in an associative container - ///////////////////////////////////////////////////////////////////////// + else + { + result = ix; + } - template - typename assoc_algorithms::iterator - assoc_algorithms::find (container &c, key_param key) - { - return c.find (key); - } + if (result >= bound) + { + throw std::out_of_range (msg); + } - ///////////////////////////////////////////////////////////////////////// - // Count occurances of an element in a container (associative version) - ///////////////////////////////////////////////////////////////////////// + return result; +} - template - typename assoc_algorithms::size_type - assoc_algorithms::count (container &c, key_param key) - { - return c.count (key); - } +///////////////////////////////////////////////////////////////////////// +// Find an element in a container (std algorithm version) +///////////////////////////////////////////////////////////////////////// + +template +typename indexing::default_algorithms::iterator +indexing::default_algorithms::find (container &c + , key_param key) +{ + return std::find (begin(c), end(c), key); +} + +///////////////////////////////////////////////////////////////////////// +// Count occurances of an element in a container (std algorithm version) +///////////////////////////////////////////////////////////////////////// + +template +typename indexing::default_algorithms::size_type +indexing::default_algorithms::count (container &c + , key_param key) +{ + return std::count (begin(c), end(c), key); +} + +///////////////////////////////////////////////////////////////////////// +// Index into a container (generic version) +///////////////////////////////////////////////////////////////////////// + +template +typename indexing::default_algorithms::reference +indexing::default_algorithms::get (container &c + , index_param ix) +{ + return c[bounds_check (c, ix, "get")]; +} + +///////////////////////////////////////////////////////////////////////// +// Assign a value at a particular index (generic version) +///////////////////////////////////////////////////////////////////////// + +template +void +indexing::default_algorithms::assign (container &c + , index_param ix + , value_param val) +{ + c[bounds_check (c, ix, "assign")] = val; +} + +///////////////////////////////////////////////////////////////////////// +// Insert at end of a container (generic version) +///////////////////////////////////////////////////////////////////////// + +template +void +indexing::default_algorithms::push_back (container &c + , value_param v) +{ + c.push_back (v); +} + +///////////////////////////////////////////////////////////////////////// +// Insert at an index in the container (generic version) +///////////////////////////////////////////////////////////////////////// + +template +void +indexing::default_algorithms::insert (container &c + , index_param i + , value_param v) +{ + // Index may range up to c.size() inclusive to allow inserting at end + c.insert (c.begin() + bounds_check (c, i, "insert", true), v); +} + +///////////////////////////////////////////////////////////////////////// +// Erase between given indexes in the container (generic version) +///////////////////////////////////////////////////////////////////////// + +template +void +indexing::default_algorithms::erase_range (container &c + , index_param from + , index_param to) +{ + // End index is one-past-the-end, so may range up to c.size() inclusive + + c.erase (c.begin() + bounds_check (c, from, "erase_range (from)") + , c.begin() + bounds_check (c, to, "erase_range (to)", true)); +} + +///////////////////////////////////////////////////////////////////////// +// Erase one element at the given index in the container (generic version) +///////////////////////////////////////////////////////////////////////// + +template +void +indexing::default_algorithms::erase_one (container &c + , index_param ix) +{ + c.erase (c.begin() + bounds_check (c, ix, "erase_one")); +} + +///////////////////////////////////////////////////////////////////////// +// Reverse the contents of a container (std algorithm version) +///////////////////////////////////////////////////////////////////////// + +template +void indexing::default_algorithms::reverse (container &c) +{ + std::reverse (begin(c), end(c)); +} + +///////////////////////////////////////////////////////////////////////// +// Sort the contents of a container (std algorithm version) +///////////////////////////////////////////////////////////////////////// + +template +void indexing::default_algorithms::sort (container &c) +{ + std::sort (begin(c), end(c)); +} + +///////////////////////////////////////////////////////////////////////// +// Visitor helper function (default version) +///////////////////////////////////////////////////////////////////////// + +template +template +void +indexing::default_algorithms +::visitor_helper (PythonClass &pyClass, Policy const &policy) +{ + container_traits::visitor_helper (pyClass, policy); +} + +///////////////////////////////////////////////////////////////////////// +// Reverse the contents of a list (member function version) +///////////////////////////////////////////////////////////////////////// + +template +void indexing::list_algorithms::reverse (container &c) +{ + c.reverse(); +} + +///////////////////////////////////////////////////////////////////////// +// Sort the contents of a container (std algorithm version) +///////////////////////////////////////////////////////////////////////// + +template +void indexing::list_algorithms::sort (container &c) +{ + c.sort(); +} + +///////////////////////////////////////////////////////////////////////// +// Index into a container (associative version) +///////////////////////////////////////////////////////////////////////// + +template +typename indexing::assoc_algorithms::reference +indexing::assoc_algorithms::get (container &c, index_param ix) +{ + iterator iter = find (c, ix); + + if (iter == end(c)) + { + // ? Is domain_error appropriate here? + throw std::domain_error + (std::string ("associative container get: key not found")); + } + + else + { + return iter->second; + } +} + +///////////////////////////////////////////////////////////////////////// +// Erase elements with the given key (associative version) +///////////////////////////////////////////////////////////////////////// + +template +void +indexing::assoc_algorithms::erase_one (container &c + , key_param key) +{ + if (c.erase (key) == 0) + { + // ? Is domain_error appropriate here? + throw std::domain_error + (std::string ("associative container erase: key not found")); + } +} + +///////////////////////////////////////////////////////////////////////// +// Assign a value at a particular index (associative version) +///////////////////////////////////////////////////////////////////////// + +template +void +indexing::assoc_algorithms::assign (container &c + , index_param ix + , value_param val) +{ + c[ix] = val; +} + +///////////////////////////////////////////////////////////////////////// +// Find an element in an associative container +///////////////////////////////////////////////////////////////////////// + +template +typename indexing::assoc_algorithms::iterator +indexing::assoc_algorithms::find (container &c, key_param key) +{ + return c.find (key); +} + +///////////////////////////////////////////////////////////////////////// +// Count occurances of an element in a container (associative version) +///////////////////////////////////////////////////////////////////////// + +template +typename indexing::assoc_algorithms::size_type +indexing::assoc_algorithms::count (container &c + , key_param key) +{ + return c.count (key); } #endif // algorithms_rmg_20030823_included diff --git a/include/boost/python/suite/indexing/container_proxy.hpp b/include/boost/python/suite/indexing/container_proxy.hpp index 55394428..fed1c2b3 100755 --- a/include/boost/python/suite/indexing/container_proxy.hpp +++ b/include/boost/python/suite/indexing/container_proxy.hpp @@ -25,6 +25,7 @@ #define container_proxy_rmg_20030826_included #include "shared_proxy_impl.hpp" +#include "element_proxy.hpp" #include #include #include @@ -60,139 +61,20 @@ public: typedef typename Container::value_type raw_value_type; - struct const_element_proxy; + typedef element_proxy value_type; + typedef value_type reference; // Already has ref. semantics - class element_proxy - { - friend class const_element_proxy; - - typedef shared_proxy proxy_type; - typedef boost::shared_ptr 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 ©) - { - 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 ©) - { - // 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_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 ©) : 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; + typedef const_element_proxy const_value_type; + typedef const_value_type const_reference; // Has ref. semantics 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 + typedef container_proxy::value_type value_type; + typedef value_type *pointer; + typedef value_type reference; // Already has reference semantics iterator (container_proxy *p, size_type i) : ptr (p), index (i) { } @@ -246,11 +128,11 @@ public: 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; + reference at (size_type index); + const_reference 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); } + reference operator[] (size_type index) { return at(index); } + const_reference operator[] (size_type index) const { return at(index); } size_type size() const { return container().size(); } size_type capacity() const { return container().capacity(); } @@ -267,8 +149,8 @@ public: void push_back (raw_value_type const ©) { insert (end(), copy); } - element_proxy pop_back () { - element_proxy result = at (end() - 1); + value_type pop_back () { + value_type result = at (end() - 1); erase (end() - 1); return result; } @@ -378,7 +260,7 @@ container_proxy } template -typename container_proxy::element_proxy +typename container_proxy::reference container_proxy ::at (size_type index) { @@ -389,11 +271,11 @@ container_proxy entry.reset (new shared_proxy (this, index)); } - return element_proxy (entry); + return reference (entry); } template -typename container_proxy::const_element_proxy +typename container_proxy::const_reference container_proxy ::at (size_type index) const { @@ -403,7 +285,7 @@ container_proxy container_proxy *mutable_this = const_cast(this); - return const_element_proxy (mutable_this->at (index)); + return const_reference (mutable_this->at (index)); } template diff --git a/include/boost/python/suite/indexing/container_suite.hpp b/include/boost/python/suite/indexing/container_suite.hpp index c8a301a2..36454c26 100755 --- a/include/boost/python/suite/indexing/container_suite.hpp +++ b/include/boost/python/suite/indexing/container_suite.hpp @@ -35,12 +35,14 @@ namespace indexing { template > struct container_suite { + typedef Algorithms algorithms; + typedef boost::python::return_value_policy default_policies; static visitor generate () { - return visitor (default_policies()); + return visitor (); } template diff --git a/include/boost/python/suite/indexing/container_traits.hpp b/include/boost/python/suite/indexing/container_traits.hpp index 5c121d96..6a570250 100755 --- a/include/boost/python/suite/indexing/container_traits.hpp +++ b/include/boost/python/suite/indexing/container_traits.hpp @@ -2,6 +2,9 @@ // // Header file container_traits.hpp // +// Traits information about entire containers for use in determining +// what Python methods to support for a container. +// // Copyright (c) 2003 Raoul M. Gough // // This material is provided "as is", with absolutely no warranty expressed @@ -26,75 +29,77 @@ #define container_traits_rmg_20030823_included #include "suite_utils.hpp" -#include "iterator_suite.hpp" +#include "iterator_traits.hpp" +#include "value_traits.hpp" #include namespace indexing { + ///////////////////////////////////////////////////////////////////////// + // Lowest common denominator traits - applicable to real containers + // and iterator pairs + ///////////////////////////////////////////////////////////////////////// + + template + struct base_container_traits + : public iterator_detail::traits_by_category + ::type + { + protected: + typedef typename + iterator_detail::traits_by_category + ::type base_type; + + BOOST_STATIC_CONSTANT (bool, is_mutable + = ! boost::is_const::value); + + public: + typedef Container container; + + typedef typename container::size_type size_type; + typedef typename container::size_type index_type; // at(), operator[] + typedef typename base_type::value_type key_type; // find, count, ... + + // *FIXME* should probably override the typedefs for iterator, + // value_type and reference with the const versions if !is_mutable + + typedef value_traits value_traits_; + + BOOST_STATIC_CONSTANT (bool, has_mutable_ref + = base_type::has_mutable_ref && is_mutable); + + BOOST_STATIC_CONSTANT (bool, has_find + = value_traits_::equality_comparable); + + // Assume the worst for everything else + BOOST_STATIC_CONSTANT (bool, has_insert = false); + BOOST_STATIC_CONSTANT (bool, has_erase = false); + BOOST_STATIC_CONSTANT (bool, has_pop_back = false); + BOOST_STATIC_CONSTANT (bool, has_push_back = false); + + // Forward visitor_helper to value_traits_ + template + static void visitor_helper (PythonClass &, Policy const &); + }; + ///////////////////////////////////////////////////////////////////////// // Traits for the iterator_pair container emulator ///////////////////////////////////////////////////////////////////////// template - struct iterator_pair_traits - : public - iterator_detail::traits_by_category::type + struct iterator_pair_traits : public base_container_traits { - 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; }; ///////////////////////////////////////////////////////////////////////// - // Lowest common denominator (almost all "real" containers would - // meet at least these requirements) + // Default container traits - almost all "real" containers would meet + // at least these requirements ///////////////////////////////////////////////////////////////////////// template - struct default_container_traits + struct default_container_traits : public base_container_traits { - protected: - static bool const is_mutable = ! boost::is_const::value; - - public: - typedef Container container; - - // *FIXME* should use value_type const and const_reference if !is_mutable - 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 IndexStyle const index_style - = ::indexing::iterator_traits::index_style; - - static bool const has_mutable_ref - = is_mutable && is_mutable_ref::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; + BOOST_STATIC_CONSTANT (bool, has_insert = is_mutable); + BOOST_STATIC_CONSTANT (bool, has_erase = is_mutable); }; ///////////////////////////////////////////////////////////////////////// @@ -104,8 +109,25 @@ namespace indexing { template struct default_sequence_traits : public default_container_traits { - static bool const has_pop_back = is_mutable; - static bool const has_push_back = is_mutable; + BOOST_STATIC_CONSTANT (bool, has_pop_back = is_mutable); + BOOST_STATIC_CONSTANT (bool, has_push_back = is_mutable); + }; + + ///////////////////////////////////////////////////////////////////////// + // Sequences within a container_proxy + ///////////////////////////////////////////////////////////////////////// + + template + struct container_proxy_traits : public default_sequence_traits + { + typedef Container container; + typedef typename container::raw_value_type value_type; // insert, ... + typedef typename container::raw_value_type key_type; // find, count, ... + typedef typename container::reference reference; // return values + + typedef value_traits value_traits_; + // Get value_traits for the reference type (i.e. element_proxy) + // to get the custom visitor_helper }; ///////////////////////////////////////////////////////////////////////// @@ -115,7 +137,8 @@ namespace indexing { template struct set_traits : public default_container_traits { - static IndexStyle const index_style = index_style_nonlinear; + BOOST_STATIC_CONSTANT (IndexStyle, index_style = index_style_nonlinear); + BOOST_STATIC_CONSTANT (bool, has_find = true); }; ///////////////////////////////////////////////////////////////////////// @@ -131,8 +154,22 @@ namespace indexing { typedef typename Container::key_type index_type; // at() typedef typename Container::key_type key_type; // find, count, ... - static IndexStyle const index_style = index_style_nonlinear; + BOOST_STATIC_CONSTANT (IndexStyle, index_style = index_style_nonlinear); + BOOST_STATIC_CONSTANT (bool, has_find = true); }; } +///////////////////////////////////////////////////////////////////////// +// Visitor helper function (foward to value_traits_ version) +///////////////////////////////////////////////////////////////////////// + +template +template +void +indexing::base_container_traits +::visitor_helper (PythonClass &pyClass, Policy const &policy) +{ + value_traits_::visitor_helper (pyClass, policy); +} + #endif // container_suite_rmg_20030823_included diff --git a/include/boost/python/suite/indexing/indexing.cpp b/include/boost/python/suite/indexing/indexing.cpp index b7582e20..1d27beaf 100755 --- a/include/boost/python/suite/indexing/indexing.cpp +++ b/include/boost/python/suite/indexing/indexing.cpp @@ -21,15 +21,27 @@ // $Id$ // +#ifndef NEWSTYLE +# define NEWSTYLE 1 +#endif + #include "container_proxy.hpp" #include "IntWrapper.hpp" +#if NEWSTYLE +#include "container_suite.hpp" +#endif + #include #include #include #include + +#if !NEWSTYLE #include #include +#endif + #include #include @@ -57,27 +69,47 @@ void pointer_increment (boost::shared_ptr const &ptr) (*ptr).increment(); } -IntWrapper *get_pointer (container_proxy >::value_type const &proxy) -{ - return &(*proxy); -} - BOOST_PYTHON_MODULE (indexing) { - boost::python::def ("trace", &IntWrapper::setTrace); + boost::python::def ("setTrace", &IntWrapper::setTrace); typedef std::vector Container; typedef container_proxy ProxyContainer; typedef boost::shared_ptr Pointer; typedef std::vector PointerContainer; - using boost::python::vector_indexing_suite; + boost::python::implicitly_convertible (); // typedef vector_indexing_suite Suite; +#if NEWSTYLE + typedef boost::python::return_value_policy + default_policies; + + // Not really the same thing - returning internal references + typedef indexing::visitor + ::algorithms + , boost::python::return_internal_reference<> > ProxySuite; + + typedef indexing::visitor + ::algorithms + , default_policies> ProxyContainerSuite; + + typedef indexing::visitor + ::algorithms + , default_policies> PointerContainerSuite; + +#else + using boost::python::vector_indexing_suite; + typedef vector_indexing_suite ProxySuite; typedef vector_indexing_suite ProxyContainerSuite; typedef vector_indexing_suite PointerContainerSuite; + boost::python::implicitly_convertible (); + + boost::python::register_ptr_to_python(); +#endif + boost::python::class_ ("Vector") .def (ProxySuite()) .def ("reserve", &Container::reserve); @@ -90,21 +122,11 @@ BOOST_PYTHON_MODULE (indexing) .def (PointerContainerSuite()) .def ("reserve", &PointerContainer::reserve); - boost::python::implicitly_convertible (); - boost::python::class_ ("IntWrapper", boost::python::init()) .def ("increment", &IntWrapper::increment) .def ("__repr__", &boost::lexical_cast) ; - // Ultimately, all of the value_type's properties should be provided - // via something like register_ptr_to_python with double-dereferencing. - // boost::python::class_ ("Container__value_type", boost::python::init()) - // .def ("increment", proxy_increment) - // .def ("__repr__", proxy_repr) - // ; - boost::python::register_ptr_to_python(); - boost::python::implicitly_convertible (); boost::python::class_ ("Pointer", boost::python::no_init) diff --git a/include/boost/python/suite/indexing/slice.cpp b/include/boost/python/suite/indexing/slice.cpp index 3247860b..823b1d71 100755 --- a/include/boost/python/suite/indexing/slice.cpp +++ b/include/boost/python/suite/indexing/slice.cpp @@ -37,28 +37,6 @@ void indexing::slice::validate () const } } -///////////////////////////////////////////////////////////////////////////// -// Slice constructor -///////////////////////////////////////////////////////////////////////////// - -indexing::slice::slice (boost::python::detail::borrowed_reference ref) - : boost::python::object (ref) - , mStart (0) - , mStep (0) - , mStop (0) - , mDirection (0) -{ - if (!PySlice_Check (this->ptr())) - { - PyErr_SetString (PyExc_TypeError - , "slice constructor: passed a non-slice object"); - - boost::python::throw_error_already_set(); - } - - // This slice object is useless until setLength is called -} - ///////////////////////////////////////////////////////////////////////////// // Set up our member variables for a sequence of a given length ///////////////////////////////////////////////////////////////////////////// diff --git a/include/boost/python/suite/indexing/slice.hpp b/include/boost/python/suite/indexing/slice.hpp index 3c626a01..40a25bbb 100755 --- a/include/boost/python/suite/indexing/slice.hpp +++ b/include/boost/python/suite/indexing/slice.hpp @@ -24,7 +24,6 @@ #ifndef slice_rmg_20030910_included #define slice_rmg_20030910_included -#include #include #include @@ -38,7 +37,8 @@ namespace indexing // A newly constructed slice object is useless until setLength is called // - slice (boost::python::detail::borrowed_reference ref); + template slice (T const &ref); + void setLength (int sequenceLength); int start() const { validate(); return mStart; } @@ -59,6 +59,25 @@ namespace indexing }; } +template +indexing::slice::slice (T const &ref) + : boost::python::object (ref) + , mStart (0) + , mStep (0) + , mStop (0) + , mDirection (0) +{ + if (!PySlice_Check (this->ptr())) + { + PyErr_SetString (PyExc_TypeError + , "slice constructor: passed a non-slice object"); + + boost::python::throw_error_already_set(); + } + + // This slice object is still useless until setLength is called +} + namespace boost { namespace python { namespace converter { // Specialized converter to handle PySlice_Type objects template<> diff --git a/include/boost/python/suite/indexing/slice_handler.hpp b/include/boost/python/suite/indexing/slice_handler.hpp index 62a2e80d..afe849d5 100755 --- a/include/boost/python/suite/indexing/slice_handler.hpp +++ b/include/boost/python/suite/indexing/slice_handler.hpp @@ -40,6 +40,8 @@ namespace indexing { static boost::python::object make_getitem (Policy const &); static boost::python::object make_setitem (Policy const &); + static boost::python::object make_delitem (Policy const &); + static boost::python::object make_extend (Policy const &); private: typedef typename Algorithms::container container; @@ -47,6 +49,8 @@ namespace indexing static boost::python::list get_slice (container &, slice); static void set_slice (container &, slice, boost::python::object); + static void del_slice (container &, slice); + static void extend (container &, boost::python::object); struct postcall_override { @@ -111,7 +115,7 @@ namespace indexing , typename Algorithms::index_param from , typename Algorithms::index_param to) { - Algorithms::erase (c, from, to); + Algorithms::erase_range (c, from, to); } }; } @@ -183,6 +187,32 @@ indexing::slice_handler return boost::python::make_function (set_slice, policy); } +///////////////////////////////////////////////////////////////////////////// +// Return a function object that implements the slice version of __delitem__ +///////////////////////////////////////////////////////////////////////////// + +template +boost::python::object +indexing::slice_handler +::make_delitem (Policy const &policy) +{ + // should we try to get funky with policy::precall? + return boost::python::make_function (del_slice, policy); +} + +///////////////////////////////////////////////////////////////////////////// +// Return a function object that implements extend +///////////////////////////////////////////////////////////////////////////// + +template +boost::python::object +indexing::slice_handler +::make_extend (Policy const &policy) +{ + // should we try to get funky with policy::precall? + return boost::python::make_function (extend, policy); +} + ///////////////////////////////////////////////////////////////////////////// // Implementation for the slice version of __getitem__ ///////////////////////////////////////////////////////////////////////////// @@ -233,7 +263,12 @@ indexing::slice_handler } typedef typename Algorithms::container_traits traits; - typedef boost::python::extract extractor; + + // Try two kinds of extractors - the first is more efficient (using + // a reference to existing object, if possible and sensible) and the + // second allowing implicit conversions. + typedef boost::python::extract extractor1; + typedef boost::python::extract extractor2; // Note: any error during this operation will probably leave the // container partially updated. This can occur (for example) if the @@ -250,7 +285,17 @@ indexing::slice_handler { if (sl.inRange (index)) { - Algorithms::assign (c, index, extractor (iterPtr->current())); + extractor1 ex1 (iterPtr->current()); + + if (ex1.check()) + { + Algorithms::assign (c, index, ex1); + } + + else + { + Algorithms::assign (c, index, extractor2 (iterPtr->current())); + } } else if (sl.step() != 1) @@ -266,9 +311,22 @@ indexing::slice_handler // Could optimize this in some cases (i.e. if the length of // the replacement sequence is known) - maybe_insert - ::template apply (c, index - , extractor (iterPtr->current())); + extractor1 ex1 (iterPtr->current()); + + if (ex1.check()) + { + maybe_insert + ::template apply (c, index, ex1); + + Algorithms::assign (c, index, ex1); + } + + else + { + maybe_insert + ::template apply + (c, index, extractor2 (iterPtr->current())); + } } index += sl.step(); @@ -293,4 +351,41 @@ indexing::slice_handler } } +///////////////////////////////////////////////////////////////////////////// +// Implementation for the slice version of __delitem__ +///////////////////////////////////////////////////////////////////////////// + +template +void +indexing::slice_handler +::del_slice (container &c, slice sl) +{ + sl.setLength (Algorithms::size (c)); // Current length of our container + + Algorithms::erase_range (c, sl.start(), sl.stop()); +} + +///////////////////////////////////////////////////////////////////////////// +// Implementation of extend +///////////////////////////////////////////////////////////////////////////// + +template +void +indexing::slice_handler +::extend (container &c, boost::python::object values) +{ + boost::python::object length + ((boost::python::detail::new_reference + (PyInt_FromLong (Algorithms::size (c))))); + + indexing::slice sl + ((boost::python::detail::new_reference + (PySlice_New + (length.ptr() + , boost::python::object().ptr() + , boost::python::object().ptr())))); + + set_slice (c, sl, values); +} + #endif // slice_handler_rmg_20030909_included diff --git a/include/boost/python/suite/indexing/testarray.py b/include/boost/python/suite/indexing/testarray.py index ca85654f..c396371f 100755 --- a/include/boost/python/suite/indexing/testarray.py +++ b/include/boost/python/suite/indexing/testarray.py @@ -22,14 +22,43 @@ # $Id$ # -from testsuite import Array, getArray +from testsuite import Array, getArray, IntWrapper, setTrace + +setTrace (0) a = getArray() -print a[0], a[1], a[2], [x for x in a], a[0:-2], a[-1:-3:-1], a[0:54:0] +print a[0], a[1], a[2], [x for x in a], a[0:-2], a[-1:-3:-1] + +try: + a[0:54:0] + +except ValueError, e: + print "Got expected ValueError:", e + pass a[1] = 4 print a[0], a[1], a[2], [x for x in a], a[0:-2], a[-1:-3:-1] -print a[0:43] +print a[0:43] # Try index beyond length + +# Try slice assignment with correct length +a[0:2] = [IntWrapper(-1), IntWrapper(-2)] +print [x for x in a] + +# Try slice assignment with overlong sequence +try: + a[0:1] = [IntWrapper(-1), IntWrapper(-2)] + +except TypeError, e: + print "Got expected TypeError:", e + pass + +# Try slice assignment with short sequence +try: + a[0:3] = [IntWrapper(-1), IntWrapper(-2)] + +except TypeError, e: + print "Got expected TypeError:", e + pass diff --git a/include/boost/python/suite/indexing/testindexing.py b/include/boost/python/suite/indexing/testindexing.py index c7b686ea..1ce87ec3 100755 --- a/include/boost/python/suite/indexing/testindexing.py +++ b/include/boost/python/suite/indexing/testindexing.py @@ -23,48 +23,89 @@ # from indexing import * +import sys -trace(0) +setTrace(0) -def test_from_empty(v): +if hasattr(sys, "gettotalrefcount"): + def dumper() : print "refcount:", sys.gettotalrefcount() + + maybe_dump_refcount = dumper +else: + def dumper() : pass + + maybe_dump_refcount = dumper + +def test_from_empty(v, outfile = sys.stdout): # v.reserve (10); - print v + print >> outfile, v v.append (IntWrapper (1)) v.append (IntWrapper (2)) v.append (IntWrapper (3)) - print v[0], v[1], v[2] + print >> outfile, v[0], v[1], v[2] try: - print v[0], v[1:][0], v[-1:][0] + print >> outfile, v[0], v[1:][0], v[-1:][0] except Exception, e: - print e + print >> outfile, e pass copy = v[1] - print "copy is %s, v[1] is %s" % (copy, v[1]) + print >> outfile, "copy is %s, v[1] is %s" % (copy, v[1]) v[1].increment() - print "copy is %s, v[1] is %s" % (copy, v[1]) + print >> outfile, "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]) + print >> outfile, "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]) + print >> outfile, "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]) + print >> outfile, "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]) + print >> outfile, "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 >> outfile, "slice[0] is %s, copy is %s, v[1] is %s" % (slice[0], copy, v[1]) - print "=============" +# if hasattr(sys, "gettotalrefcount"): +# for x in range(20): +# v[:] = [1,2,3,4] +# maybe_dump_refcount() + +# for x in range(9): +# v[:] = [1,2,3,4] +# maybe_dump_refcount() + + print >> outfile, "=============" + +#test_from_empty (Vector_proxy()) + +class write_eater: + def write (self, str): + pass + +# Run everything through once to settle reference counters +test_from_empty (Vector(), write_eater()) +test_from_empty (ProxyVector(), write_eater()) +test_from_empty (PointerVector(), write_eater()) +test_from_empty ([], write_eater()) + +# Run again with output (and ref-count dumping, if possible) +maybe_dump_refcount() test_from_empty (Vector()) +maybe_dump_refcount() + test_from_empty (ProxyVector()) +maybe_dump_refcount() + test_from_empty (PointerVector()) +maybe_dump_refcount() + test_from_empty ([]) +maybe_dump_refcount() diff --git a/include/boost/python/suite/indexing/testsuite.cpp b/include/boost/python/suite/indexing/testsuite.cpp index 2f11aa2d..3fe6ce10 100755 --- a/include/boost/python/suite/indexing/testsuite.cpp +++ b/include/boost/python/suite/indexing/testsuite.cpp @@ -36,6 +36,7 @@ #include #include "iterator_pair.hpp" +#include "container_proxy.hpp" indexing::iterator_pair getArray() { @@ -63,7 +64,8 @@ BOOST_PYTHON_MODULE(testsuite) boost::python::class_ ("IntWrapper", boost::python::init()) .def ("increment", &IntWrapper::increment) - .def ("__repr__", repr); + .def ("__repr__", repr) + .def ("__cmp__", compare) ; typedef std::vector Container1; @@ -96,4 +98,9 @@ BOOST_PYTHON_MODULE(testsuite) // deletes! boost::python::class_("Vector_ref") .def (indexing::container_suite::generate (boost::python::return_internal_reference<>())); + + typedef container_proxy > Container6; + + boost::python::class_("Vector_proxy") + .def (indexing::container_suite::generate ()); } diff --git a/include/boost/python/suite/indexing/testvector.py b/include/boost/python/suite/indexing/testvector.py index 4e4b161f..72f17a22 100755 --- a/include/boost/python/suite/indexing/testvector.py +++ b/include/boost/python/suite/indexing/testvector.py @@ -22,18 +22,60 @@ # $Id$ # -from testsuite import Vector +from testsuite import Vector, Vector_ref, setTrace -v = Vector() +def test_vector(v): + v.append(1) + v.append(2) + v.append(3) -v.append(1) -v.append(2) -v.append(3) + print v[0], v[1], v[2], [x for x in v] -print v[0], v[1], v[2], [x for x in v] + v[1] = 4 -v[1] = 4 + print v[0], v[1], v[2], [x for x in v], v[0:2] -print v[0], v[1], v[2], [x for x in v] + # Try slice assignment with equal lengths + v[0:2] = [9, 8] + print [x for x in v] -print v[0:2] + # Try slice assignment with shorter replacement + v[0:2] = [7] + print [x for x in v] + + # Try slice assignment with longer replacement + v[0:1] = [6, 5, 4] + print [x for x in v] + + # Try element deletion + del v[0] + print [x for x in v] + + # Try slice deletion + del v[0:2] + print [x for x in v] + + try: + del v[3] + + except IndexError, e: + print "Got expected exception:", e + + print [x for x in v] + + del v[0:999] + print [x for x in v] + + v.append (3) + print v[0] + del v[:] + print [x for x in v] + +print "Plain vector:" +print "=============" +test_vector (Vector()) + +print "Ref vector:" +print "===========" +setTrace(0) +test_vector (Vector_ref()) diff --git a/include/boost/python/suite/indexing/vector_indexing_suite_ext.cpp b/include/boost/python/suite/indexing/vector_indexing_suite_ext.cpp index 086d000b..e44d34a8 100755 --- a/include/boost/python/suite/indexing/vector_indexing_suite_ext.cpp +++ b/include/boost/python/suite/indexing/vector_indexing_suite_ext.cpp @@ -2,7 +2,7 @@ #include #include #include -#include "container_proxy.hpp" +#include "container_suite.hpp" using namespace boost::python; @@ -23,11 +23,6 @@ std::string x_value(X const& x) return "gotya " + x.s; } -X *get_pointer (container_proxy >::value_type const &proxy) -{ - return &(*proxy); -} - BOOST_PYTHON_MODULE(vector_indexing_suite_ext) { class_("X") @@ -35,6 +30,7 @@ BOOST_PYTHON_MODULE(vector_indexing_suite_ext) .def(init()) .def(init()) .def("__repr__", &X::repr) + .def("__eq__", &X::operator==) .def("reset", &X::reset) .def("foo", &X::foo) ; @@ -45,12 +41,8 @@ BOOST_PYTHON_MODULE(vector_indexing_suite_ext) typedef std::vector RawContainer; typedef container_proxy Container; - boost::python::register_ptr_to_python(); - - implicitly_convertible(); - class_("XVec") - .def(vector_indexing_suite()) + .def(indexing::container_suite::generate()) ; // Compile check only... diff --git a/include/boost/python/suite/indexing/visitor.hpp b/include/boost/python/suite/indexing/visitor.hpp index d759cecd..79ca0a8b 100755 --- a/include/boost/python/suite/indexing/visitor.hpp +++ b/include/boost/python/suite/indexing/visitor.hpp @@ -28,14 +28,68 @@ #include #include +#include +#include namespace indexing { + namespace detail { + template + struct precall_only : public boost::python::default_call_policies + { + // This policies struct uses default policies for everything + // except precall, which must be provided by the template + // argument. + + precall_only () : mPrecall () { } + explicit precall_only (PrecallPolicy const ©) : mPrecall (copy) { } + + bool precall (PyObject *args) { return mPrecall.precall (args); } + bool precall (PyObject *args) const { return mPrecall.precall (args); } + + private: + PrecallPolicy mPrecall; + }; + } + + ////////////////////////////////////////////////////////////////////////// + // __len__ dummy + ////////////////////////////////////////////////////////////////////////// + + template + struct maybe_add_len { + template + static void apply (PythonClass &, Algorithms const &, Policy const &) { } + }; + + ////////////////////////////////////////////////////////////////////////// + // __len__ real + ////////////////////////////////////////////////////////////////////////// + + template<> + struct maybe_add_len { + template + static void apply (PythonClass &pyClass + , Algorithms const & + , Policy const &policy) + { + pyClass.def ("__len__", &Algorithms::size, policy); + } + }; + + ////////////////////////////////////////////////////////////////////////// + // __getitem__ dummy + ////////////////////////////////////////////////////////////////////////// + template struct maybe_add_getitem { template static void apply (PythonClass &, Algorithms const &, Policy const &) { } }; + ////////////////////////////////////////////////////////////////////////// + // __getitem__ no-slice + ////////////////////////////////////////////////////////////////////////// + template<> struct maybe_add_getitem { template @@ -47,6 +101,10 @@ namespace indexing { } }; + ////////////////////////////////////////////////////////////////////////// + // __getitem__ with slice + ////////////////////////////////////////////////////////////////////////// + template<> struct maybe_add_getitem { template @@ -60,12 +118,20 @@ namespace indexing { } }; + ////////////////////////////////////////////////////////////////////////// + // __setitem__ dummy + ////////////////////////////////////////////////////////////////////////// + template struct maybe_add_setitem { template static void apply (PythonClass &, Algorithms const &, Policy const &) { } }; + ////////////////////////////////////////////////////////////////////////// + // __setitem__ no-slice + ////////////////////////////////////////////////////////////////////////// + template<> struct maybe_add_setitem { template @@ -77,6 +143,10 @@ namespace indexing { } }; + ////////////////////////////////////////////////////////////////////////// + // __setitem__ with slice + ////////////////////////////////////////////////////////////////////////// + template<> struct maybe_add_setitem { template @@ -90,12 +160,62 @@ namespace indexing { } }; + ////////////////////////////////////////////////////////////////////////// + // __delitem__ dummy + ////////////////////////////////////////////////////////////////////////// + + template + struct maybe_add_delitem { + template + static void apply (PythonClass &, Algorithms const &, Policy const &) { } + }; + + ////////////////////////////////////////////////////////////////////////// + // __delitem__ no-slice + ////////////////////////////////////////////////////////////////////////// + + template<> + struct maybe_add_delitem { + template + static void apply (PythonClass &pyClass + , Algorithms const & + , Policy const &policy) + { + pyClass.def ("__delitem__", &Algorithms::erase_one, policy); + } + }; + + ////////////////////////////////////////////////////////////////////////// + // __delitem__ with slice + ////////////////////////////////////////////////////////////////////////// + + template<> + struct maybe_add_delitem { + template + static void apply (PythonClass &pyClass + , Algorithms const & + , Policy const &policy) + { + pyClass.def ("__delitem__", &Algorithms::erase_one, policy); + pyClass.def ("__delitem__" + , slice_handler::make_delitem (policy)); + } + }; + + ////////////////////////////////////////////////////////////////////////// + // __iter__ dummy + ////////////////////////////////////////////////////////////////////////// + template struct maybe_add_iter { template static void apply (PythonClass &, Algorithms const &, Policy const &) { } }; + ////////////////////////////////////////////////////////////////////////// + // __iter__ real + ////////////////////////////////////////////////////////////////////////// + template<> struct maybe_add_iter { template @@ -103,18 +223,29 @@ namespace indexing { , Algorithms const & , Policy const &policy) { + // *FIXME* seperate precall and postcall portions of the + // policy (precall when generating the range object, postcall + // when returing from range.next()) pyClass.def ("__iter__" , boost::python::range (Algorithms::begin , Algorithms::end)); } }; + ////////////////////////////////////////////////////////////////////////// + // append dummy + ////////////////////////////////////////////////////////////////////////// + template struct maybe_add_append { template static void apply (PythonClass &, Algorithms const &, Policy const &) { } }; + ////////////////////////////////////////////////////////////////////////// + // append real + ////////////////////////////////////////////////////////////////////////// + template<> struct maybe_add_append { template @@ -126,6 +257,155 @@ namespace indexing { } }; + ////////////////////////////////////////////////////////////////////////// + // extend dummy + ////////////////////////////////////////////////////////////////////////// + + template + struct maybe_add_extend { + template + static void apply (PythonClass &, Algorithms const &, Policy const &) { } + }; + + ////////////////////////////////////////////////////////////////////////// + // extend real + ////////////////////////////////////////////////////////////////////////// + + template<> + struct maybe_add_extend { + template + static void apply (PythonClass &pyClass + , Algorithms const & + , Policy const &policy) + { + pyClass.def ("extend" + , slice_handler::make_extend (policy)); + } + }; + + ////////////////////////////////////////////////////////////////////////// + // index dummy + ////////////////////////////////////////////////////////////////////////// + + template + struct maybe_add_index { + template + static void apply (PythonClass &, Algorithms const &, Policy const &) { } + }; + + ////////////////////////////////////////////////////////////////////////// + // index real + ////////////////////////////////////////////////////////////////////////// + + namespace detail { + template + typename Algorithms::index_type + get_index (typename Algorithms::container &c + , typename Algorithms::key_param key) + { + typename Algorithms::iterator temp (Algorithms::find (c, key)); + + if (temp == Algorithms::end(c)) + { + PyErr_SetString (PyExc_ValueError + , "get_index: element not found"); + + boost::python::throw_error_already_set (); + } + + return std::distance (Algorithms::begin (c), temp); + } + } + + template<> + struct maybe_add_index { + template + static void apply (PythonClass &pyClass + , Algorithms const & + , Policy const &policy) + { + pyClass.def ("index", detail::get_index, policy); + } + }; + + ////////////////////////////////////////////////////////////////////////// + // count dummy + ////////////////////////////////////////////////////////////////////////// + + template + struct maybe_add_count { + template + static void apply (PythonClass &, Algorithms const &, Policy const &) { } + }; + + ////////////////////////////////////////////////////////////////////////// + // count real (sequences without indexing) + ////////////////////////////////////////////////////////////////////////// + + template<> + struct maybe_add_count { + template + static void apply (PythonClass &pyClass + , Algorithms const & + , Policy const &policy) + { + pyClass.def ("count", Algorithms::count, policy); + } + }; + + + ////////////////////////////////////////////////////////////////////////// + // count real (sequences with indexing) + ////////////////////////////////////////////////////////////////////////// + + template<> + struct maybe_add_count { + template + static void apply (PythonClass &pyClass + , Algorithms const & + , Policy const &policy) + { + // This is identical to the index_style_none version. Doing it + // this way avoids using a partial specialization for + // + pyClass.def ("count", Algorithms::count, policy); + } + }; + + ////////////////////////////////////////////////////////////////////////// + // count real (associative containers). add has_key + ////////////////////////////////////////////////////////////////////////// + + namespace detail { + template + bool has_key (typename Algorithms::container &c + , typename Algorithms::key_param key) + { + return Algorithms::find (c, key) != Algorithms::end (c); + } + } + + template<> + struct maybe_add_count { + template + static void apply (PythonClass &pyClass + , Algorithms const & + , Policy const &policy) + { + // Nearest equivalent is has_key, since Python dictionaries + // have at most one value for a key. + pyClass.def ("has_key", detail::has_key, policy); + + // Maybe this makes sense for multimap or multiset. Then again, + // maybe they should always return a list of elements for a key? + pyClass.def ("count", Algorithms::count, policy); + } + }; + + ////////////////////////////////////////////////////////////////////////// + // Do-all visitor + ////////////////////////////////////////////////////////////////////////// + template class visitor : public boost::python::def_visitor< visitor< Algorithms, Policy > > @@ -136,23 +416,49 @@ namespace indexing { typedef Algorithms algorithms; typedef typename algorithms::container_traits traits; - visitor (Policy const &policy) : mPolicy (policy) { } + explicit visitor (Policy const &policy = Policy()) : mPolicy (policy) { } template void visit (PythonClass &pyClass) const { + detail::precall_only precallPolicy (mPolicy); + + // Note - this will add __len__ for anything that can determine + // its size, even if that might be inefficient (e.g. have linear + // time complexity). It might be better to add a new feature + // selection flag to the container_traits to make this + // configurable. + maybe_add_len + ::apply (pyClass, algorithms(), precallPolicy); + maybe_add_getitem ::apply (pyClass, algorithms(), mPolicy); maybe_add_setitem ::apply (pyClass, algorithms(), mPolicy); + maybe_add_delitem + ::apply (pyClass, algorithms(), mPolicy); + maybe_add_iter<((traits::index_style != index_style_linear) && traits::has_copyable_iter)> ::apply (pyClass, algorithms(), mPolicy); maybe_add_append - ::apply (pyClass, algorithms(), mPolicy); + ::apply (pyClass, algorithms(), precallPolicy); + + maybe_add_extend<(traits::has_insert + && traits::index_style == index_style_linear)> + ::apply (pyClass, algorithms(), precallPolicy); + + maybe_add_index<(traits::has_find + && (traits::index_style == index_style_linear))> + ::apply (pyClass, algorithms(), precallPolicy); + + maybe_add_count + ::apply (pyClass, algorithms(), precallPolicy); + + Algorithms::visitor_helper (pyClass, mPolicy); } }; } From 1a33896b71dcbdcc6d83d4f012587c028fa83864 Mon Sep 17 00:00:00 2001 From: Raoul Gough Date: Thu, 18 Sep 2003 17:46:43 +0000 Subject: [PATCH 35/39] Avoid consequential failures from __setslice__ with non-iterable value [SVN r1565] --- .../boost/python/suite/indexing/vector_indexing_suite.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/include/boost/python/suite/indexing/vector_indexing_suite.py b/include/boost/python/suite/indexing/vector_indexing_suite.py index 1905d7df..9394319a 100755 --- a/include/boost/python/suite/indexing/vector_indexing_suite.py +++ b/include/boost/python/suite/indexing/vector_indexing_suite.py @@ -131,6 +131,13 @@ reset >>> print_xvec(v) [ a z d e ] +##################################################################### +# Slice: replace [:] with correct result of previous test +##################################################################### +>>> v[:] = [ 'a', 'z', 'd', 'e' ] +>>> print_xvec(v) +[ a z d e ] + ##################################################################### # Slice: replace [0:2] with a list ##################################################################### From b8dd3b324aaeb17e705c810210f320a5f1b8355e Mon Sep 17 00:00:00 2001 From: Raoul Gough Date: Thu, 18 Sep 2003 17:49:27 +0000 Subject: [PATCH 36/39] Remove .def of __eq__, since find and count now implemented as C++ functions [SVN r1566] --- .../boost/python/suite/indexing/vector_indexing_suite_ext.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/include/boost/python/suite/indexing/vector_indexing_suite_ext.cpp b/include/boost/python/suite/indexing/vector_indexing_suite_ext.cpp index e44d34a8..7b435d4c 100755 --- a/include/boost/python/suite/indexing/vector_indexing_suite_ext.cpp +++ b/include/boost/python/suite/indexing/vector_indexing_suite_ext.cpp @@ -30,7 +30,6 @@ BOOST_PYTHON_MODULE(vector_indexing_suite_ext) .def(init()) .def(init()) .def("__repr__", &X::repr) - .def("__eq__", &X::operator==) .def("reset", &X::reset) .def("foo", &X::foo) ; From dc65b0702c1626bff757f6cff8dee29697e061d7 Mon Sep 17 00:00:00 2001 From: Raoul Gough Date: Thu, 18 Sep 2003 17:57:18 +0000 Subject: [PATCH 37/39] Removing obsolete/out of date files [SVN r1567] --- include/boost/python/suite/indexing/CONTENTS | 26 --------------- .../boost/python/suite/indexing/vis.hpp.patch | 33 ------------------- 2 files changed, 59 deletions(-) delete mode 100755 include/boost/python/suite/indexing/CONTENTS delete mode 100644 include/boost/python/suite/indexing/vis.hpp.patch diff --git a/include/boost/python/suite/indexing/CONTENTS b/include/boost/python/suite/indexing/CONTENTS deleted file mode 100755 index bb9756db..00000000 --- a/include/boost/python/suite/indexing/CONTENTS +++ /dev/null @@ -1,26 +0,0 @@ - -container_suite.hpp Top-level do-all suite for all supported container types -container_traits.hpp Container traits -iterator_suite.hpp (misnamed) Iterator traits -suite_utils.hpp Utilities to abstract away container interface diffs -iterator_pair.hpp Container emulator using iterator pairs -testsuite.cpp Python extension class for testing the container suite -slice_handler.hpp Python slice interpreter - - -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 -=========== - -indexing_suite.cpp Traits tests -containers.txt Analysis of Python sequence vs. C++ containers -testlist.py Test behaviour of real Python lists diff --git a/include/boost/python/suite/indexing/vis.hpp.patch b/include/boost/python/suite/indexing/vis.hpp.patch deleted file mode 100644 index 8a8b429a..00000000 --- a/include/boost/python/suite/indexing/vis.hpp.patch +++ /dev/null @@ -1,33 +0,0 @@ -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 elem(v); -+ extract elem(v); - // try if elem is an exact Data - if (elem.check()) - { From 7d061a18aec4cf1606b0f300147d9cbfac0b33dd Mon Sep 17 00:00:00 2001 From: Raoul Gough Date: Thu, 18 Sep 2003 17:58:11 +0000 Subject: [PATCH 38/39] Updated for new indexing suite, with identical results for proxy container, pointer container and real Python list [SVN r1568] --- .../boost/python/suite/indexing/sample.out | 45 ++++++++++++------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/include/boost/python/suite/indexing/sample.out b/include/boost/python/suite/indexing/sample.out index 1ac1712e..0584c7d8 100644 --- a/include/boost/python/suite/indexing/sample.out +++ b/include/boost/python/suite/indexing/sample.out @@ -1,26 +1,22 @@ - +# +# Sample output from the testindexing.py script, using python_d +# (Python interpreter debug build) for reference leak detection +# + +refcount: 8837 + 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 +slice[0] is 6, copy is 6, v[1] is 6 +slice[0] is 7, copy is 7, v[1] is 7 +slice[0] is 9, copy is 7, 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 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 -============= - +refcount: 8837 + 1 2 3 1 2 3 copy is 2, v[1] is 2 @@ -31,6 +27,19 @@ 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 ============= +refcount: 8837 + +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 +============= +refcount: 8837 [] 1 2 3 1 2 3 @@ -42,3 +51,7 @@ 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 ============= +refcount: 8837 +Adding parser accelerators ... +Done. +[4120 refs] From 04cb2cd39abbadab46e07d6e13f464d6c411b292 Mon Sep 17 00:00:00 2001 From: Raoul Gough Date: Tue, 7 Oct 2003 17:28:24 +0000 Subject: [PATCH 39/39] Initial revision [SVN r1644] --- .../suite/indexing/detail/test_performance.py | 85 +++++++++ .../indexing/detail2/python_iterator.cpp | 168 ++++++++++++++++++ .../python/suite/indexing/detail2/slice.cpp | 65 +++++++ 3 files changed, 318 insertions(+) create mode 100755 include/boost/python/suite/indexing/detail/test_performance.py create mode 100755 include/boost/python/suite/indexing/detail2/python_iterator.cpp create mode 100755 include/boost/python/suite/indexing/detail2/slice.cpp diff --git a/include/boost/python/suite/indexing/detail/test_performance.py b/include/boost/python/suite/indexing/detail/test_performance.py new file mode 100755 index 00000000..9c6f43c8 --- /dev/null +++ b/include/boost/python/suite/indexing/detail/test_performance.py @@ -0,0 +1,85 @@ +#!/usr/bin/python +# -*- mode:python -*- +# +# Python module test_performance.py +# +# Copyright (c) 2003 Raoul M. Gough +# +# Use, modification and distribution is subject to the Boost Software +# License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy +# at http://www.boost.org/LICENSE_1_0.txt) +# +# History +# ======= +# 2003/10/ 5 rmg File creation +# +# $Id$ +# + +from time import clock +from testlinear import Vector + +def fillByAppend (container, size): + append = container.append + for count in range (size): + append (count) + +def fillByExtend (container, size): + extend = container.extend + for count in range (size / 100): + extend (range (count * 100, count * 100 + 100)) + +def search (container, item, iterations): + index = container.index + for count in range (iterations): + index (item) + +def reverse_part (container, start, end): + end -= 1 + while start < end: + temp = container[start] + container[start] = container[end] + container[end] = temp + start += 1 + end -= 1 + +def reorder (container, block = 10): + for count in range (len(container) / block): + reverse_part (container, count * block, count * block + block) + +def testPerformance (container): + size = 1000000 + start = clock() + fillByExtend (container, size) + print "Fill:", clock() - start + + start = clock() + search (container, container[size - 1], 10) + print "Search:", clock() - start + + start = clock() + reorder (container, 8) + reorder (container, 16) + reorder (container, 32) + print "Reorder:", clock() - start + +# print container[:20] +# print container[-20:] + + start = clock() + container.sort() + print "Sort:", clock() - start + + +print "list =====" +testPerformance ([]) +v1 = Vector() +v1.reserve (1000000) +print "vector (with reserve) =====" +testPerformance (v1) + +print "list =====" +testPerformance ([]) +print "vector (no reserve) =====" +testPerformance (Vector()) + diff --git a/include/boost/python/suite/indexing/detail2/python_iterator.cpp b/include/boost/python/suite/indexing/detail2/python_iterator.cpp new file mode 100755 index 00000000..015171a4 --- /dev/null +++ b/include/boost/python/suite/indexing/detail2/python_iterator.cpp @@ -0,0 +1,168 @@ +// -*- mode:c++ -*- +// +// Module python_iterator.cpp +// +// Copyright (c) 2003 Raoul M. Gough +// +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy +// at http://www.boost.org/LICENSE_1_0.txt) +// +// History +// ======= +// 2003/ 9/10 rmg File creation +// +// $Id$ +// + +#include + +//////////////////////////////////////////////////////////////////////////// +// python_iterator factory +/////////////////////////////////////////////////////////////////////////// + +std::auto_ptr +boost::python::indexing::make_iterator (boost::python::object temp) +{ + std::auto_ptr result; + + try + { + result.reset (new python_iter_iterator (temp)); + } + + catch (boost::python::error_already_set const &) + { + PyErr_Clear (); + + try + { + result.reset (new python_getitem_iterator (temp)); + } + + catch (boost::python::error_already_set const &) + { + PyErr_Clear (); + } + } + + return result; +} + +//////////////////////////////////////////////////////////////////////////// +// Base class (virtual) destructor +/////////////////////////////////////////////////////////////////////////// + +boost::python::indexing::python_iterator::~python_iterator () +{ +} + +//////////////////////////////////////////////////////////////////////////// +// python_getitem_iterator constructor +/////////////////////////////////////////////////////////////////////////// + +boost::python::indexing::python_getitem_iterator +::python_getitem_iterator (boost::python::object obj) + : mGetitemMethod (obj.attr ("__getitem__")) + , mIndex (0) + , mCurrent() +{ +} + +//////////////////////////////////////////////////////////////////////////// +// Get our next item (if any) +/////////////////////////////////////////////////////////////////////////// + +bool boost::python::indexing::python_getitem_iterator::next () +{ + bool result = true; // Assume success + + try + { + mCurrent = mGetitemMethod (mIndex); + ++mIndex; + } + + catch (boost::python::error_already_set const &) + { + if (PyErr_ExceptionMatches (PyExc_IndexError)) + { + // Eat this exception + PyErr_Clear (); + mCurrent = boost::python::object (); + result = false; + } + + else + { + // Pass it up the line + throw; + } + } + + return result; +} + +//////////////////////////////////////////////////////////////////////////// +// Return our current item +/////////////////////////////////////////////////////////////////////////// + +boost::python::object +boost::python::indexing::python_getitem_iterator::current () const +{ + return mCurrent; +} + +//////////////////////////////////////////////////////////////////////////// +// python_iter_iterator constructor +/////////////////////////////////////////////////////////////////////////// + +boost::python::indexing::python_iter_iterator +::python_iter_iterator (boost::python::object obj) + : mNextMethod (obj.attr ("__iter__")().attr ("next")) + , mCurrent() +{ +} + +//////////////////////////////////////////////////////////////////////////// +// Get our next item (if any) +/////////////////////////////////////////////////////////////////////////// + +bool boost::python::indexing::python_iter_iterator::next () +{ + bool result = true; // Assume success + + try + { + mCurrent = mNextMethod (); + } + + catch (boost::python::error_already_set const &) + { + if (PyErr_ExceptionMatches (PyExc_StopIteration)) + { + // Eat this exception + PyErr_Clear (); + mCurrent = boost::python::object (); + result = false; + } + + else + { + // Pass it up the line + throw; + } + } + + return result; +} + +//////////////////////////////////////////////////////////////////////////// +// Return our current item +/////////////////////////////////////////////////////////////////////////// + +boost::python::object +boost::python::indexing::python_iter_iterator::current () const +{ + return mCurrent; +} diff --git a/include/boost/python/suite/indexing/detail2/slice.cpp b/include/boost/python/suite/indexing/detail2/slice.cpp new file mode 100755 index 00000000..cfd740bb --- /dev/null +++ b/include/boost/python/suite/indexing/detail2/slice.cpp @@ -0,0 +1,65 @@ +// -*- mode:c++ -*- +// +// Module slice.cpp +// +// Copyright (c) 2003 Raoul M. Gough +// +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy +// at http://www.boost.org/LICENSE_1_0.txt) +// +// History +// ======= +// 2003/ 9/10 rmg File creation +// +// $Id$ +// + +#include + +///////////////////////////////////////////////////////////////////////////// +// Check that setLength has been called, and throw otherwise +///////////////////////////////////////////////////////////////////////////// + +void boost::python::indexing::slice::validate () const +{ + if (mDirection == 0) + { + PyErr_SetString (PyExc_RuntimeError + , "slice access attempted before setLength called"); + boost::python::throw_error_already_set(); + } +} + +///////////////////////////////////////////////////////////////////////////// +// Set up our member variables for a sequence of a given length +///////////////////////////////////////////////////////////////////////////// + +void boost::python::indexing::slice::setLength (int sequenceLength) +{ + PySlice_GetIndices ((PySliceObject *) this->ptr() + , sequenceLength + , &mStart + , &mStop + , &mStep); + + if (mStep == 0) + { + // Can happen with Python prior to 2.3 + PyErr_SetString (PyExc_ValueError, "slice step cannot be zero"); + boost::python::throw_error_already_set (); + } + + mStart = std::max (0, std::min (sequenceLength, mStart)); + mStop = std::max (0, std::min (sequenceLength, mStop)); + mDirection = (mStep > 0) ? 1 : -1; +} + +///////////////////////////////////////////////////////////////////////////// +// Check if an index is within the range of this slice +///////////////////////////////////////////////////////////////////////////// + +bool boost::python::indexing::slice::inRange (int index) +{ + return ((mStop - index) * mDirection) > 0; +}