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

Optional flags parameter to visitor allows container features to be suppressed

[SVN r20874]
This commit is contained in:
Raoul Gough
2003-11-19 23:07:01 +00:00
parent bdde13d1bc
commit 0bc4ee884f
14 changed files with 261 additions and 70 deletions

View File

@@ -805,9 +805,13 @@ namespace boost { namespace python { namespace indexing {
};
}
#endif
template<class Container, class Traits = container_proxy_traits<Container> >
template <
class Container
, int Flags = 0
, class Traits = container_proxy_traits<Container>
>
struct container_proxy_suite
: container_suite<Container, default_algorithms<Traits> >
: container_suite<Container, Flags, default_algorithms<Traits> >
{
};

View File

@@ -31,16 +31,18 @@ namespace boost { namespace python { namespace indexing {
template <
class Container
, int Flags = 0
, class Algorithms
= algo_selector<Container>
>
struct container_suite
: public visitor<Algorithms, default_container_policies>
: public visitor<Algorithms, default_container_policies, Flags>
{
typedef Algorithms algorithms;
template<typename Policy>
static visitor<Algorithms, Policy> with_policies (Policy const &policy)
static
visitor<Algorithms, Policy, Flags> with_policies (Policy const &policy)
{
return visitor <Algorithms, Policy> (policy);
}

View File

@@ -46,8 +46,13 @@ namespace boost { namespace python { namespace indexing {
}
#endif
template<class Container, class Traits = default_sequence_traits<Container> >
struct deque_suite : container_suite<Container, default_algorithms<Traits> >
template <
class Container
, int Flags = 0
, class Traits = default_sequence_traits<Container>
>
struct deque_suite
: container_suite<Container, Flags, default_algorithms<Traits> >
{
};

View File

@@ -201,9 +201,13 @@ namespace boost { namespace python { namespace indexing {
}
#endif
template<class Container, class Traits = base_container_traits<Container> >
template <
class Container
, int Flags = 0
, class Traits = base_container_traits<Container>
>
struct iterator_range_suite
: container_suite<Container, default_algorithms<Traits> >
: container_suite<Container, Flags, default_algorithms<Traits> >
{
};

View File

@@ -76,8 +76,13 @@ namespace boost { namespace python { namespace indexing {
}
#endif
template<class Container, class Traits = default_sequence_traits<Container> >
struct list_suite : container_suite<Container, list_algorithms<Traits> >
template <
class Container
, int Flags = 0
, class Traits = default_sequence_traits<Container>
>
struct list_suite
: container_suite<Container, Flags, list_algorithms<Traits> >
{
};
@@ -98,7 +103,7 @@ namespace boost { namespace python { namespace indexing {
template<typename ContainerTraits, typename Ovr>
void list_algorithms<ContainerTraits, Ovr>::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

View File

@@ -126,8 +126,13 @@ namespace boost { namespace python { namespace indexing {
}
#endif
template<class Container, class Traits = map_traits<Container> >
struct map_suite : container_suite<Container, map_algorithms<Traits> >
template <
class Container
, int Flags = 0
, class Traits = map_traits<Container>
>
struct map_suite
: container_suite<Container, Flags, map_algorithms<Traits> >
{
};

View File

@@ -114,8 +114,13 @@ namespace boost { namespace python { namespace indexing {
}
#endif
template<class Container, class Traits = set_traits<Container> >
struct set_suite : container_suite<Container, set_algorithms<Traits> >
template <
class Container
, int Flags = 0
, class Traits = set_traits<Container>
>
struct set_suite
: container_suite<Container, Flags, set_algorithms<Traits> >
{
};

View File

@@ -21,22 +21,23 @@
#include <boost/type_traits.hpp>
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<typename T>

View File

@@ -46,8 +46,13 @@ namespace boost { namespace python { namespace indexing {
}
#endif
template<class Container, class Traits = default_sequence_traits<Container> >
struct vector_suite : container_suite<Container, default_algorithms<Traits> >
template <
class Container
, int Flags = 0
, class Traits = default_sequence_traits<Container>
>
struct vector_suite
: container_suite<Container, Flags, default_algorithms<Traits> >
{
};

View File

@@ -26,7 +26,21 @@
#include <boost/bind.hpp>
#include <functional>
#define ICE_AND(a, b) ::boost::type_traits::ice_and <(a), (b)>::value
#define ICE_NOT(a) ::boost::type_traits::ice_not <static_cast<bool>(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<typename PrecallPolicy>
struct precall_only : public boost::python::default_call_policies
@@ -76,7 +90,7 @@ namespace boost { namespace python { namespace indexing {
// __getitem__ dummy
//////////////////////////////////////////////////////////////////////////
template<index_style_t style>
template<bool doit, bool with_slice>
struct maybe_add_getitem {
template<class PythonClass, class Algorithms, class Policy>
static void apply (PythonClass &, Algorithms const &, Policy const &) { }
@@ -87,7 +101,7 @@ namespace boost { namespace python { namespace indexing {
//////////////////////////////////////////////////////////////////////////
template<>
struct maybe_add_getitem<index_style_nonlinear> {
struct maybe_add_getitem<true, false> {
template<class PythonClass, class Algorithms, class Policy>
static void apply (
PythonClass &pyClass
@@ -103,7 +117,7 @@ namespace boost { namespace python { namespace indexing {
//////////////////////////////////////////////////////////////////////////
template<>
struct maybe_add_getitem<index_style_linear> {
struct maybe_add_getitem<true, true> {
template<class PythonClass, class Algorithms, class Policy>
static void apply (
PythonClass &pyClass
@@ -121,7 +135,7 @@ namespace boost { namespace python { namespace indexing {
// __setitem__ dummy
//////////////////////////////////////////////////////////////////////////
template<bool doit, index_style_t style>
template<bool doit, bool with_slice>
struct maybe_add_setitem {
template<class PythonClass, class Algorithms, class Policy>
static void apply (PythonClass &, Algorithms const &, Policy const &) { }
@@ -132,7 +146,7 @@ namespace boost { namespace python { namespace indexing {
//////////////////////////////////////////////////////////////////////////
template<>
struct maybe_add_setitem<true, index_style_nonlinear> {
struct maybe_add_setitem<true, false> {
template<class PythonClass, class Algorithms, class Policy>
static void apply (
PythonClass &pyClass
@@ -148,7 +162,7 @@ namespace boost { namespace python { namespace indexing {
//////////////////////////////////////////////////////////////////////////
template<>
struct maybe_add_setitem<true, index_style_linear> {
struct maybe_add_setitem<true, true> {
template<class PythonClass, class Algorithms, class Policy>
static void apply (
PythonClass &pyClass
@@ -166,7 +180,7 @@ namespace boost { namespace python { namespace indexing {
// __delitem__ dummy
//////////////////////////////////////////////////////////////////////////
template<bool doit, index_style_t style>
template<bool doit, bool with_slicing>
struct maybe_add_delitem {
template<class PythonClass, class Algorithms, class Policy>
static void apply (PythonClass &, Algorithms const &, Policy const &) { }
@@ -177,7 +191,7 @@ namespace boost { namespace python { namespace indexing {
//////////////////////////////////////////////////////////////////////////
template<>
struct maybe_add_delitem<true, index_style_nonlinear> {
struct maybe_add_delitem<true, false> {
template<class PythonClass, class Algorithms, class Policy>
static void apply (
PythonClass &pyClass
@@ -193,7 +207,7 @@ namespace boost { namespace python { namespace indexing {
//////////////////////////////////////////////////////////////////////////
template<>
struct maybe_add_delitem<true, index_style_linear> {
struct maybe_add_delitem<true, true> {
template<class PythonClass, class Algorithms, class Policy>
static void apply (
PythonClass &pyClass
@@ -245,7 +259,7 @@ namespace boost { namespace python { namespace indexing {
// sort dummy
//////////////////////////////////////////////////////////////////////////
template<bool doit, bool lessthan_comparable>
template<bool doit>
struct maybe_add_sort {
template<class PythonClass, class Algorithms, class Policy>
static void apply (PythonClass &, Algorithms const &, Policy const &) { }
@@ -256,7 +270,7 @@ namespace boost { namespace python { namespace indexing {
//////////////////////////////////////////////////////////////////////////
template<>
struct maybe_add_sort<true, true> {
struct maybe_add_sort<true> {
template<class PythonClass, class Algorithms, class Policy>
static void apply (
PythonClass &pyClass
@@ -474,9 +488,9 @@ namespace boost { namespace python { namespace indexing {
// Do-all visitor
//////////////////////////////////////////////////////////////////////////
template<class Algorithms, class Policy>
template<class Algorithms, class Policy, int Flags = 0>
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 <class PythonClass>
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<traits::has_copyable_iter>
::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<traits::index_style>
maybe_add_getitem <has_indexing, has_slicing>
::apply (pyClass, algorithms(), m_policy);
maybe_add_setitem<traits::has_mutable_ref, traits::index_style>
::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<traits::has_erase, traits::index_style>
maybe_add_delitem<ICE_AND (traits::has_erase, has_indexing), has_slicing>
::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<traits::is_reorderable>
::apply (pyClass, algorithms(), precallPolicy);
maybe_add_reverse <
ICE_AND (traits::is_reorderable, ICE_NOT (Flags & disable_reorder))
>::apply (pyClass, algorithms(), precallPolicy);
maybe_add_append<traits::has_push_back>
::apply (pyClass, algorithms(), precallPolicy);
maybe_add_insert<traits::has_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<traits::has_find, traits::index_style>
::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

View File

@@ -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 ;

42
test/test_vector_disable.cpp Executable file
View File

@@ -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 <boost/python/suite/indexing/container_suite.hpp>
#include <boost/python/suite/indexing/vector.hpp>
#include <vector>
#include <boost/python/class.hpp>
#include <boost/python/module.hpp>
#include <boost/python/def.hpp>
BOOST_PYTHON_MODULE(test_vector_disable_ext)
{
namespace indexing = boost::python::indexing;
typedef std::vector<int> 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<Container1, indexing::minimum_support>
Suite1;
#else
// For broken compilers - explicit selection of algorithms/traits
typedef indexing::vector_suite<Container1, indexing::minimum_support>
Suite1;
#endif
boost::python::class_<Container1>("Vector_disable").def (Suite1());
}

View File

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

View File

@@ -70,7 +70,7 @@ BOOST_PYTHON_MODULE(test_vector_shared_ext)
typedef indexing::default_sequence_traits<Container1, value_traits_>
container_traits_;
typedef indexing::default_algorithms<container_traits_> algorithms_;
typedef indexing::container_suite<Container1, algorithms_> Suite1;
typedef indexing::container_suite<Container1, 0, algorithms_> Suite1;
boost::python::class_<Container1>("Vector_shared")
.def (Suite1())