From 0bc4ee884f021a63e41f11d46f33aba071b6cdde Mon Sep 17 00:00:00 2001 From: Raoul Gough Date: Wed, 19 Nov 2003 23:07:01 +0000 Subject: [PATCH] Optional flags parameter to visitor allows container features to be suppressed [SVN r20874] --- .../python/suite/indexing/container_proxy.hpp | 8 +- .../python/suite/indexing/container_suite.hpp | 6 +- include/boost/python/suite/indexing/deque.hpp | 9 +- .../python/suite/indexing/iterator_range.hpp | 8 +- include/boost/python/suite/indexing/list.hpp | 11 +- include/boost/python/suite/indexing/map.hpp | 9 +- include/boost/python/suite/indexing/set.hpp | 9 +- .../python/suite/indexing/suite_utils.hpp | 23 ++-- .../boost/python/suite/indexing/vector.hpp | 9 +- .../boost/python/suite/indexing/visitor.hpp | 123 ++++++++++++------ test/Jamfile | 1 + test/test_vector_disable.cpp | 42 ++++++ test/test_vector_disable.py | 71 ++++++++++ test/test_vector_shared.cpp | 2 +- 14 files changed, 261 insertions(+), 70 deletions(-) create mode 100755 test/test_vector_disable.cpp create mode 100644 test/test_vector_disable.py diff --git a/include/boost/python/suite/indexing/container_proxy.hpp b/include/boost/python/suite/indexing/container_proxy.hpp index c0a58272..96c60f44 100755 --- a/include/boost/python/suite/indexing/container_proxy.hpp +++ b/include/boost/python/suite/indexing/container_proxy.hpp @@ -805,9 +805,13 @@ namespace boost { namespace python { namespace indexing { }; } #endif - template > + template < + class Container + , int Flags = 0 + , class Traits = container_proxy_traits + > struct container_proxy_suite - : container_suite > + : container_suite > { }; diff --git a/include/boost/python/suite/indexing/container_suite.hpp b/include/boost/python/suite/indexing/container_suite.hpp index b3f93b70..57f3ed15 100755 --- a/include/boost/python/suite/indexing/container_suite.hpp +++ b/include/boost/python/suite/indexing/container_suite.hpp @@ -31,16 +31,18 @@ namespace boost { namespace python { namespace indexing { template < class Container + , int Flags = 0 , class Algorithms = algo_selector > struct container_suite - : public visitor + : public visitor { typedef Algorithms algorithms; template - static visitor with_policies (Policy const &policy) + static + visitor with_policies (Policy const &policy) { return visitor (policy); } diff --git a/include/boost/python/suite/indexing/deque.hpp b/include/boost/python/suite/indexing/deque.hpp index ee58abde..748094b3 100755 --- a/include/boost/python/suite/indexing/deque.hpp +++ b/include/boost/python/suite/indexing/deque.hpp @@ -46,8 +46,13 @@ namespace boost { namespace python { namespace indexing { } #endif - template > - struct deque_suite : container_suite > + template < + class Container + , int Flags = 0 + , class Traits = default_sequence_traits + > + struct deque_suite + : container_suite > { }; diff --git a/include/boost/python/suite/indexing/iterator_range.hpp b/include/boost/python/suite/indexing/iterator_range.hpp index bfb1b23b..b9cb9a34 100755 --- a/include/boost/python/suite/indexing/iterator_range.hpp +++ b/include/boost/python/suite/indexing/iterator_range.hpp @@ -201,9 +201,13 @@ namespace boost { namespace python { namespace indexing { } #endif - template > + template < + class Container + , int Flags = 0 + , class Traits = base_container_traits + > struct iterator_range_suite - : container_suite > + : container_suite > { }; diff --git a/include/boost/python/suite/indexing/list.hpp b/include/boost/python/suite/indexing/list.hpp index 50b79b87..25f42f5f 100755 --- a/include/boost/python/suite/indexing/list.hpp +++ b/include/boost/python/suite/indexing/list.hpp @@ -76,8 +76,13 @@ namespace boost { namespace python { namespace indexing { } #endif - template > - struct list_suite : container_suite > + template < + class Container + , int Flags = 0 + , class Traits = default_sequence_traits + > + struct list_suite + : container_suite > { }; @@ -98,7 +103,7 @@ namespace boost { namespace python { namespace indexing { template void list_algorithms::sort (container &c) { - typedef typename container_traits::value_traits_ value_traits_; + typedef typename self_type::container_traits::value_traits_ value_traits_; typedef typename value_traits_::less comparison; #if BOOST_WORKAROUND (BOOST_MSVC, == 1200) // MSVC6 doesn't have a templated sort member in list, so we just diff --git a/include/boost/python/suite/indexing/map.hpp b/include/boost/python/suite/indexing/map.hpp index e2b306a0..b37c4b02 100755 --- a/include/boost/python/suite/indexing/map.hpp +++ b/include/boost/python/suite/indexing/map.hpp @@ -126,8 +126,13 @@ namespace boost { namespace python { namespace indexing { } #endif - template > - struct map_suite : container_suite > + template < + class Container + , int Flags = 0 + , class Traits = map_traits + > + struct map_suite + : container_suite > { }; diff --git a/include/boost/python/suite/indexing/set.hpp b/include/boost/python/suite/indexing/set.hpp index 0dd2bd8b..816d2808 100755 --- a/include/boost/python/suite/indexing/set.hpp +++ b/include/boost/python/suite/indexing/set.hpp @@ -114,8 +114,13 @@ namespace boost { namespace python { namespace indexing { } #endif - template > - struct set_suite : container_suite > + template < + class Container + , int Flags = 0 + , class Traits = set_traits + > + struct set_suite + : container_suite > { }; diff --git a/include/boost/python/suite/indexing/suite_utils.hpp b/include/boost/python/suite/indexing/suite_utils.hpp index 05e6e55b..65606601 100755 --- a/include/boost/python/suite/indexing/suite_utils.hpp +++ b/include/boost/python/suite/indexing/suite_utils.hpp @@ -21,22 +21,23 @@ #include namespace boost { namespace python { namespace indexing { -#if !BOOST_MSVC - enum index_style_t { - 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) - }; -#else - // MSVC seems to have problems with static member variable constants - // of enumerated types, where it doesn't believe that an expression - // like (traits::index_style == index_style_linear) is a - // compile-time constant. However, the problem doesn't exist for +#if BOOST_WORKAROUND (BOOST_MSVC, BOOST_TESTED_AT (1310)) \ + || (defined (__GNUC__) && (__GNUC__ < 3)) + // MSVC and GCC 2.96 seem to have problems comparing enumerated + // values in a static constant expression, and don't believe that an + // expression like (traits::index_style >= index_style_nonlinear) is + // a compile-time constant. However, the problem doesn't exist for // int. typedef int index_style_t; index_style_t const index_style_none = 0; index_style_t const index_style_nonlinear = 1; index_style_t const index_style_linear = 2; +#else + enum index_style_t { + 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) + }; #endif template diff --git a/include/boost/python/suite/indexing/vector.hpp b/include/boost/python/suite/indexing/vector.hpp index 684f81d0..b67d781f 100755 --- a/include/boost/python/suite/indexing/vector.hpp +++ b/include/boost/python/suite/indexing/vector.hpp @@ -46,8 +46,13 @@ namespace boost { namespace python { namespace indexing { } #endif - template > - struct vector_suite : container_suite > + template < + class Container + , int Flags = 0 + , class Traits = default_sequence_traits + > + struct vector_suite + : container_suite > { }; diff --git a/include/boost/python/suite/indexing/visitor.hpp b/include/boost/python/suite/indexing/visitor.hpp index 578c952f..33965a9e 100755 --- a/include/boost/python/suite/indexing/visitor.hpp +++ b/include/boost/python/suite/indexing/visitor.hpp @@ -26,7 +26,21 @@ #include #include +#define ICE_AND(a, b) ::boost::type_traits::ice_and <(a), (b)>::value +#define ICE_NOT(a) ::boost::type_traits::ice_not (a)>::value +// undef'd at end of header + namespace boost { namespace python { namespace indexing { + enum visitor_flags { + disable_len = 1 + , disable_slices = 2 + , disable_search = 4 + , disable_reorder = 8 + , disable_extend = 16 + , disable_insert = 32 + , minimum_support = 0xffff // Disable all optional features + }; + namespace detail { template struct precall_only : public boost::python::default_call_policies @@ -76,7 +90,7 @@ namespace boost { namespace python { namespace indexing { // __getitem__ dummy ////////////////////////////////////////////////////////////////////////// - template + template struct maybe_add_getitem { template static void apply (PythonClass &, Algorithms const &, Policy const &) { } @@ -87,7 +101,7 @@ namespace boost { namespace python { namespace indexing { ////////////////////////////////////////////////////////////////////////// template<> - struct maybe_add_getitem { + struct maybe_add_getitem { template static void apply ( PythonClass &pyClass @@ -103,7 +117,7 @@ namespace boost { namespace python { namespace indexing { ////////////////////////////////////////////////////////////////////////// template<> - struct maybe_add_getitem { + struct maybe_add_getitem { template static void apply ( PythonClass &pyClass @@ -121,7 +135,7 @@ namespace boost { namespace python { namespace indexing { // __setitem__ dummy ////////////////////////////////////////////////////////////////////////// - template + template struct maybe_add_setitem { template static void apply (PythonClass &, Algorithms const &, Policy const &) { } @@ -132,7 +146,7 @@ namespace boost { namespace python { namespace indexing { ////////////////////////////////////////////////////////////////////////// template<> - struct maybe_add_setitem { + struct maybe_add_setitem { template static void apply ( PythonClass &pyClass @@ -148,7 +162,7 @@ namespace boost { namespace python { namespace indexing { ////////////////////////////////////////////////////////////////////////// template<> - struct maybe_add_setitem { + struct maybe_add_setitem { template static void apply ( PythonClass &pyClass @@ -166,7 +180,7 @@ namespace boost { namespace python { namespace indexing { // __delitem__ dummy ////////////////////////////////////////////////////////////////////////// - template + template struct maybe_add_delitem { template static void apply (PythonClass &, Algorithms const &, Policy const &) { } @@ -177,7 +191,7 @@ namespace boost { namespace python { namespace indexing { ////////////////////////////////////////////////////////////////////////// template<> - struct maybe_add_delitem { + struct maybe_add_delitem { template static void apply ( PythonClass &pyClass @@ -193,7 +207,7 @@ namespace boost { namespace python { namespace indexing { ////////////////////////////////////////////////////////////////////////// template<> - struct maybe_add_delitem { + struct maybe_add_delitem { template static void apply ( PythonClass &pyClass @@ -245,7 +259,7 @@ namespace boost { namespace python { namespace indexing { // sort dummy ////////////////////////////////////////////////////////////////////////// - template + template struct maybe_add_sort { template static void apply (PythonClass &, Algorithms const &, Policy const &) { } @@ -256,7 +270,7 @@ namespace boost { namespace python { namespace indexing { ////////////////////////////////////////////////////////////////////////// template<> - struct maybe_add_sort { + struct maybe_add_sort { template static void apply ( PythonClass &pyClass @@ -474,9 +488,9 @@ namespace boost { namespace python { namespace indexing { // Do-all visitor ////////////////////////////////////////////////////////////////////////// - template + template class visitor - : public boost::python::def_visitor< visitor< Algorithms, Policy > > + : public boost::python::def_visitor< visitor< Algorithms, Policy, Flags > > { Policy m_policy; @@ -487,6 +501,16 @@ namespace boost { namespace python { namespace indexing { explicit visitor (Policy const &policy = Policy()) : m_policy (policy) { } + private: + BOOST_STATIC_CONSTANT ( + bool, has_indexing = traits::index_style >= index_style_nonlinear); + + BOOST_STATIC_CONSTANT ( + bool, has_slicing = ICE_AND ( + traits::index_style == index_style_linear + , ICE_NOT (Flags & disable_slices))); + + public: template void visit (PythonClass &pyClass) const { @@ -494,61 +518,78 @@ namespace boost { namespace python { namespace indexing { // 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); + // time complexity). Disable by setting disable_len in Flags + maybe_add_len < + ICE_AND ( + traits::has_copyable_iter + , ICE_NOT (Flags & disable_len)) + >::apply (pyClass, algorithms(), precallPolicy); - maybe_add_getitem + maybe_add_getitem ::apply (pyClass, algorithms(), m_policy); - maybe_add_setitem - ::apply (pyClass, algorithms(), m_policy); + maybe_add_setitem < + ICE_AND (traits::has_mutable_ref, has_indexing) + , has_slicing + >::apply (pyClass, algorithms(), m_policy); - maybe_add_delitem + maybe_add_delitem ::apply (pyClass, algorithms(), m_policy); maybe_add_iter< - type_traits::ice_and < - traits::index_style != index_style_linear - , traits::has_copyable_iter - >::value + ICE_AND ( + traits::index_style != index_style_linear + , traits::has_copyable_iter) >::apply (pyClass, algorithms(), m_policy); maybe_add_sort < - traits::is_reorderable, value_traits_::lessthan_comparable + ICE_AND ( + ICE_AND ( + traits::is_reorderable + , value_traits_::lessthan_comparable) + , ICE_NOT (Flags & disable_reorder)) >::apply (pyClass, algorithms(), precallPolicy); - maybe_add_reverse - ::apply (pyClass, algorithms(), precallPolicy); + maybe_add_reverse < + ICE_AND (traits::is_reorderable, ICE_NOT (Flags & disable_reorder)) + >::apply (pyClass, algorithms(), precallPolicy); maybe_add_append ::apply (pyClass, algorithms(), precallPolicy); - maybe_add_insert - ::apply (pyClass, algorithms(), precallPolicy); + maybe_add_insert < + ICE_AND (traits::has_insert, ICE_NOT (Flags & disable_insert)) + >::apply (pyClass, algorithms(), precallPolicy); maybe_add_extend < - type_traits::ice_and < - traits::index_style == index_style_linear - , traits::has_insert - >::value + ICE_AND ( + ICE_AND ( + traits::index_style == index_style_linear + , traits::has_insert) + , ICE_NOT (Flags & disable_extend)) >::apply (pyClass, algorithms(), precallPolicy); maybe_add_index < - type_traits::ice_and < - traits::index_style == index_style_linear - , traits::has_find - >::value + ICE_AND ( + ICE_AND ( + traits::index_style == index_style_linear + , traits::has_find) + , ICE_NOT (Flags & disable_search)) >::apply (pyClass, algorithms(), precallPolicy); - maybe_add_count - ::apply (pyClass, algorithms(), precallPolicy); + maybe_add_count < + ICE_AND ( + traits::has_find + , ICE_NOT (Flags & disable_search)) + , traits::index_style + >::apply (pyClass, algorithms(), precallPolicy); Algorithms::visitor_helper (pyClass, m_policy); } }; } } } +#undef ICE_AND +#undef ICE_NOT + #endif // BOOST_PYTHON_INDEXING_VISITOR_HPP diff --git a/test/Jamfile b/test/Jamfile index 479be43a..01e313dd 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -60,6 +60,7 @@ bpl-test test_deque_ref : test_deque_ref.py test_deque_ext.cpp ; bpl-test test_deque_plain : test_deque_plain.py test_deque_ext.cpp ; bpl-test test_indexing_const ; bpl-test test_vector_shared ; +bpl-test test_vector_disable ; bpl-test test_array : test_array.py test_array_ext.cpp ; bpl-test test_array_ref : test_array_ref.py test_array_ext.cpp ; bpl-test test_list_plain : test_list_plain.py test_list_ext.cpp ; diff --git a/test/test_vector_disable.cpp b/test/test_vector_disable.cpp new file mode 100755 index 00000000..b2b359db --- /dev/null +++ b/test/test_vector_disable.cpp @@ -0,0 +1,42 @@ +// Module test_vector_disable.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/11/19 rmg File creation +// +// $Id$ +// + +#include +#include +#include +#include +#include +#include + +BOOST_PYTHON_MODULE(test_vector_disable_ext) +{ + namespace indexing = boost::python::indexing; + + typedef std::vector Container1; + + // Generate a vector suite with all optional support disabled + +#if !defined (BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) + // Normal case (automatic algorithm and traits selection) + typedef indexing::container_suite + Suite1; +#else + // For broken compilers - explicit selection of algorithms/traits + typedef indexing::vector_suite + Suite1; +#endif + + boost::python::class_("Vector_disable").def (Suite1()); +} diff --git a/test/test_vector_disable.py b/test/test_vector_disable.py new file mode 100644 index 00000000..ef70b371 --- /dev/null +++ b/test/test_vector_disable.py @@ -0,0 +1,71 @@ +# Python module test_vector_disable.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/11/19 rmg File creation +# +# $Id$ +# + +'''>>> from test_vector_disable_ext import * +>>> v = Vector_disable() +>>> v.append (1) +>>> v.append (2) +>>> v.append (3) +>>> v.append (4) +>>> del v[0] +>>> print [ x for x in v ] +[2, 3, 4] +>>> v[0] = 5 +>>> print [ x for x in v ] +[5, 3, 4] +>>> assert getattr (v, "len", None) == None +>>> assert getattr (v, "sort", None) == None +>>> assert getattr (v, "reverse", None) == None +>>> assert getattr (v, "index", None) == None +>>> assert getattr (v, "count", None) == None +>>> assert getattr (v, "insert", None) == None +>>> assert getattr (v, "extend", None) == None +>>> try: +... s = v[:] +... print "__getitem__ supports slices (should be disabled)" +... except TypeError, e: +... print "Got expected exception" +... +Got expected exception +>>> try: +... v[:1] = [1] +... print "__setitem__ supports slices (should be disabled)" +... except TypeError, e: +... print "Got expected exception" +... +Got expected exception +>>> try: +... del v[:] +... print "__delitem__ supports slices (should be disabled)" +... except TypeError, e: +... print "Got expected exception" +... +Got expected exception +''' + +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print 'running...' + import sys + status = run()[0] + if (status == 0): print "Done." + sys.exit(status) diff --git a/test/test_vector_shared.cpp b/test/test_vector_shared.cpp index 20b8b573..df8f4fc0 100755 --- a/test/test_vector_shared.cpp +++ b/test/test_vector_shared.cpp @@ -70,7 +70,7 @@ BOOST_PYTHON_MODULE(test_vector_shared_ext) typedef indexing::default_sequence_traits container_traits_; typedef indexing::default_algorithms algorithms_; - typedef indexing::container_suite Suite1; + typedef indexing::container_suite Suite1; boost::python::class_("Vector_shared") .def (Suite1())