From f30fde3a522672c4ffc947ad34cf433a6ece4961 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Sat, 29 Jun 2002 19:24:11 +0000 Subject: [PATCH] list implementation [SVN r14261] --- Jamfile | 1 + .../boost/python/converter/arg_to_python.hpp | 31 ++- .../converter/pytype_arg_from_python.hpp | 99 ++++++++++ include/boost/python/detail/raw_pyobject.hpp | 29 +++ .../boost/python/detail/string_literal.hpp | 77 ++++++++ include/boost/python/list.hpp | 179 ++++++++++++++++++ include/boost/python/module.hpp | 2 +- include/boost/python/object_attributes.hpp | 4 +- include/boost/python/object_core.hpp | 164 ++++++++-------- include/boost/python/object_items.hpp | 8 +- include/boost/python/object_operators.hpp | 8 +- include/boost/python/object_slices.hpp | 36 ++-- include/boost/python/objects.hpp | 1 + include/boost/python/objects2.hpp | 100 +--------- include/boost/python/proxy.hpp | 4 +- src/list.cpp | 105 ++++++++++ src/object/class.cpp | 4 +- src/object/function.cpp | 2 +- src/object_operators.cpp | 10 +- src/object_protocol.cpp | 31 +-- src/objects2.cpp | 147 -------------- test/Jamfile | 2 + test/list.cpp | 131 +++++++++++++ 23 files changed, 777 insertions(+), 398 deletions(-) create mode 100644 include/boost/python/converter/pytype_arg_from_python.hpp create mode 100644 include/boost/python/detail/raw_pyobject.hpp create mode 100644 include/boost/python/detail/string_literal.hpp create mode 100644 include/boost/python/list.hpp create mode 100644 src/list.cpp create mode 100644 test/list.cpp diff --git a/Jamfile b/Jamfile index 72e4b3ec..5ebd1f0a 100644 --- a/Jamfile +++ b/Jamfile @@ -13,6 +13,7 @@ if $(UNIX) && ( $(OS) = AIX ) dll bpl : + src/list.cpp src/aix_init_module.cpp src/converter/from_python.cpp src/converter/registry.cpp diff --git a/include/boost/python/converter/arg_to_python.hpp b/include/boost/python/converter/arg_to_python.hpp index e4a2bfaf..a7c845d7 100755 --- a/include/boost/python/converter/arg_to_python.hpp +++ b/include/boost/python/converter/arg_to_python.hpp @@ -14,6 +14,7 @@ # include # include # include +# include # include // Bring in specializations # include @@ -73,6 +74,11 @@ namespace detail template struct select_arg_to_python { + // Special handling for char const[N]; interpret them as char + // const* for the sake of conversion + BOOST_STATIC_CONSTANT( + bool, is_string = python::detail::is_string_literal::value); + BOOST_STATIC_CONSTANT( bool, manager = is_object_manager::value); @@ -89,22 +95,27 @@ namespace detail typedef typename unwrap_pointer::type unwrapped_ptr; typedef typename mpl::select_type< - manager - , object_manager_arg_to_python + is_string + , arg_to_python , typename mpl::select_type< - ptr - , pointer_deep_arg_to_python + manager + , object_manager_arg_to_python , typename mpl::select_type< - ptr_wrapper - , pointer_shallow_arg_to_python + ptr + , pointer_deep_arg_to_python , typename mpl::select_type< - ref_wrapper - , reference_arg_to_python - , value_arg_to_python + ptr_wrapper + , pointer_shallow_arg_to_python + , typename mpl::select_type< + ref_wrapper + , reference_arg_to_python + , value_arg_to_python + >::type >::type >::type >::type - >::type type; + >::type + type; }; } diff --git a/include/boost/python/converter/pytype_arg_from_python.hpp b/include/boost/python/converter/pytype_arg_from_python.hpp new file mode 100644 index 00000000..ade4fd66 --- /dev/null +++ b/include/boost/python/converter/pytype_arg_from_python.hpp @@ -0,0 +1,99 @@ +// Copyright David Abrahams 2002. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#ifndef PYTYPE_ARG_FROM_PYTHON_DWA2002628_HPP +# define PYTYPE_ARG_FROM_PYTHON_DWA2002628_HPP + +# include + +// +// arg_from_python converters for Python type wrappers, to be used as +// base classes for specializations. +// +namespace boost { namespace python { namespace converter { + +template +struct pytype_arg_from_python +{ + pytype_arg_from_python(PyObject*); + bool convertible() const; + private: + PyObject* m_src; +}; + +// rvalue converter base +template +struct pytype_wrapper_value_arg_from_python + : pytype_arg_from_python +{ + typedef Wrapper result_type; + + pytype_wrapper_value_arg_from_python(PyObject*); + Wrapper operator()(PyObject*) const; +}; + +// Special case for Wrapper& - must store an lvalue internally. This +// OK because the entire state of the object is actually in the Python +// object. +template +struct pytype_wrapper_ref_arg_from_python + : pytype_arg_from_python +{ + typedef Wrapper& result_type; + + pytype_wrapper_ref_arg_from_python(PyObject*); + Wrapper& operator()(PyObject*) const; + private: + mutable Wrapper m_result; +}; + +// +// implementations +// + +template +inline pytype_arg_from_python::pytype_arg_from_python(PyObject* x) + : m_src(x) +{ +} + +template +inline bool pytype_arg_from_python::convertible() const +{ + return PyObject_IsInstance(m_src, (PyObject*)python_type); +} + +template +pytype_wrapper_value_arg_from_python::pytype_wrapper_value_arg_from_python( + PyObject* p) + : pytype_arg_from_python(p) +{ +} + +template +Wrapper pytype_wrapper_value_arg_from_python::operator()( + PyObject* x) const +{ + return Wrapper(python::detail::borrowed_reference(x)); +} + +template +pytype_wrapper_ref_arg_from_python::pytype_wrapper_ref_arg_from_python( + PyObject* p) + : pytype_arg_from_python(p) + , m_result(python::detail::borrowed_reference(p)) +{ +} + +template +Wrapper& pytype_wrapper_ref_arg_from_python::operator()( + PyObject* x) const +{ + return m_result; +} + +}}} // namespace boost::python::converter + +#endif // PYTYPE_ARG_FROM_PYTHON_DWA2002628_HPP diff --git a/include/boost/python/detail/raw_pyobject.hpp b/include/boost/python/detail/raw_pyobject.hpp new file mode 100644 index 00000000..5d87da56 --- /dev/null +++ b/include/boost/python/detail/raw_pyobject.hpp @@ -0,0 +1,29 @@ +// Copyright David Abrahams 2002. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#ifndef RAW_PYOBJECT_DWA2002628_HPP +# define RAW_PYOBJECT_DWA2002628_HPP + +namespace boost { namespace python { namespace detail { + +// +// Define some types which we can use to get around the vagaries of +// PyObject*. We will use these to initialize object instances, and +// keep them in namespace detail to make sure they stay out of the +// hands of users. That is much simpler than trying to grant +// friendship to all the appropriate parties. +// + +// New references are checked for null +struct new_reference_t; +typedef new_reference_t* new_reference; + +// Borrowed references are assumed to be non-null +struct borrowed_reference_t; +typedef borrowed_reference_t* borrowed_reference; + +}}} // namespace boost::python::detail + +#endif // RAW_PYOBJECT_DWA2002628_HPP diff --git a/include/boost/python/detail/string_literal.hpp b/include/boost/python/detail/string_literal.hpp new file mode 100644 index 00000000..d8230bb8 --- /dev/null +++ b/include/boost/python/detail/string_literal.hpp @@ -0,0 +1,77 @@ +// Copyright David Abrahams 2002. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#ifndef STRING_LITERAL_DWA2002629_HPP +# define STRING_LITERAL_DWA2002629_HPP + +# include +# include +# include +# include + +namespace boost { namespace python { namespace detail { + +# ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION +template +struct is_string_literal +{ + BOOST_STATIC_CONSTANT(bool, value = false); +}; + +# if !defined(__MWERKS__) || __MWERKS__ > 0x2407 +template +struct is_string_literal +{ + BOOST_STATIC_CONSTANT(bool, value = true); +}; +# else +// CWPro7 has trouble with the array type deduction above +template +struct is_string_literal + : is_same +{ +}; +# endif +# else +template +struct string_literal_helper +{ + typedef char (&yes_string_literal)[1]; + typedef char (&no_string_literal)[2]; + + template + struct apply + { + typedef apply self; + static T x; + static yes_string_literal check(char const*); + static no_string_literal check(char*); + static no_string_literal check(void const volatile*); + + BOOST_STATIC_CONSTANT( + bool, value = sizeof(self::check(x)) == sizeof(yes_string_literal)); + }; +}; + +template <> +struct string_literal_helper +{ + template + struct apply + { + BOOST_STATIC_CONSTANT(bool, value = false); + }; +}; + +template +struct is_string_literal + : string_literal_helper::value>::apply +{ +}; +# endif + +}}} // namespace boost::python::detail + +#endif // STRING_LITERAL_DWA2002629_HPP diff --git a/include/boost/python/list.hpp b/include/boost/python/list.hpp new file mode 100644 index 00000000..30189f8e --- /dev/null +++ b/include/boost/python/list.hpp @@ -0,0 +1,179 @@ +// Copyright David Abrahams 2002. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#ifndef LIST_DWA2002627_HPP +# define LIST_DWA2002627_HPP + +# include +# include + +namespace boost { namespace python { + +class list : public object +{ +# if !defined(BOOST_MSVC) || BOOST_MSVC > 1200 + typedef object const& object_cref; +# else + typedef object object_cref; +# endif + public: + BOOST_PYTHON_DECL list(); // new list + explicit BOOST_PYTHON_DECL list(object_cref sequence); // new list initialized from sequence's items + + template + explicit list(T const& sequence) + : object(list::call(object(sequence))) + { + } + + BOOST_PYTHON_DECL void append(object_cref); // append object to end + + template + void append(T const& x) + { + this->append(object(x)); + } + + BOOST_PYTHON_DECL long count(object_cref value) const; // return number of occurrences of value + + template + long count(T const& value) const + { + return this->count(object(value)); + } + + BOOST_PYTHON_DECL void extend(object_cref sequence); // extend list by appending sequence elements + + template + void extend(T const& x) + { + this->extend(object(x)); + } + + BOOST_PYTHON_DECL long index(object_cref value) const; // return index of first occurrence of value + + template + long index(T const& x) const + { + return this->index(object(x)); + } + + BOOST_PYTHON_DECL void insert(int index, object_cref); // insert object before index + BOOST_PYTHON_DECL void insert(object const& index, object_cref); + + template + void insert(int index, T const& x) // insert object before index + { + this->insert(index, object(x)); + } + + template + void insert(object const& index, T const& x) // insert object before index + { + this->insert(index, object(x)); + } + + BOOST_PYTHON_DECL object pop(); // remove and return item at index (default last) + BOOST_PYTHON_DECL object pop(long index); + BOOST_PYTHON_DECL object pop(object const& index); + + BOOST_PYTHON_DECL void remove(object_cref value); // remove first occurrence of value + + template + void remove(T const& value) + { + this->remove(object(value)); + } + + BOOST_PYTHON_DECL void reverse(); // reverse *IN PLACE* + + BOOST_PYTHON_DECL void sort(); // sort *IN PLACE*; if given, cmpfunc(x, y) -> -1, 0, 1 + BOOST_PYTHON_DECL void sort(object_cref cmpfunc); + + template + void sort(T const& value) + { + this->sort(object(value)); + } + + public: // implementation detail -- for internal use only + explicit list(detail::borrowed_reference); + explicit list(detail::new_reference); + + private: + static BOOST_PYTHON_DECL detail::new_reference call(object const&); +}; + +// +// Converter Specializations +// +template struct arg_from_python; + +template <> +struct arg_from_python + : converter::pytype_wrapper_value_arg_from_python +{ + typedef converter::pytype_wrapper_value_arg_from_python base; + typedef list result_type; + + arg_from_python(PyObject* p) : base(p) {} +}; + +template <> +struct arg_from_python + : arg_from_python +{ + arg_from_python(PyObject* p) + : arg_from_python(p) {} +}; + +template <> +struct arg_from_python + : converter::pytype_wrapper_ref_arg_from_python +{ + typedef converter::pytype_wrapper_ref_arg_from_python base; + typedef list result_type; + + arg_from_python(PyObject* p) + : base(p) {} +}; + +namespace converter +{ + template struct is_object_manager; + + template <> + struct is_object_manager + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + + template struct return_from_python; + template <> + struct return_from_python + { + typedef list result_type; + + result_type operator()(PyObject* x) const + { + return list(python::detail::new_reference(x)); + } + }; +} + +// +// list implementation +// +inline list::list(detail::borrowed_reference p) + : object(p) +{} + +inline list::list(detail::new_reference p) + : object(p) +{} + +}} // namespace boost::python + +#endif // LIST_DWA2002627_HPP diff --git a/include/boost/python/module.hpp b/include/boost/python/module.hpp index a4dad490..8ee63485 100644 --- a/include/boost/python/module.hpp +++ b/include/boost/python/module.hpp @@ -76,7 +76,7 @@ inline module& module::setattr(const char* name, handle<> const& x) inline module& module::add(PyTypeObject* x) { - this->base::add(x); + this->base::add(handle<>(borrowed(x))); return *this; } diff --git a/include/boost/python/object_attributes.hpp b/include/boost/python/object_attributes.hpp index c10608cb..4d3c2a7d 100755 --- a/include/boost/python/object_attributes.hpp +++ b/include/boost/python/object_attributes.hpp @@ -30,14 +30,14 @@ struct attribute_policies : const_attribute_policies template inline object_attribute object_operators::attr(char const* name) { - object_cref x = *static_cast(this); + object_cref2 x = *static_cast(this); return object_attribute(x, name); } template inline const_object_attribute object_operators::attr(char const* name) const { - object_cref x = *static_cast(this); + object_cref2 x = *static_cast(this); return const_object_attribute(x, name); } diff --git a/include/boost/python/object_core.hpp b/include/boost/python/object_core.hpp index b0b9813f..d0228cc9 100755 --- a/include/boost/python/object_core.hpp +++ b/include/boost/python/object_core.hpp @@ -11,6 +11,8 @@ # include # include # include +# include +# include # include namespace boost { namespace python { @@ -68,35 +70,8 @@ namespace api }; # endif - // - // object_handle -- get the handle to construct the object with, - // based on whether T is a proxy or not - // - template - struct object_handle - { - template - static handle<> get(T const& x) - { - return handle<>( - python::borrowed( - python::allow_null( // null check is already done - converter::arg_to_python(x).get()) - ) - ); - } - }; - - template <> - struct object_handle - { - template - static handle<> get(proxy const& x) - { - return x.operator object().ptr(); - } - }; - + template struct object_initializer; + // A way to turn a conrete type T into a type dependent on U. This // keeps conforming compilers from complaining about returning an // incomplete T from a template member function (which must be @@ -108,24 +83,24 @@ namespace api }; class object; - typedef handle<> const& (object::*bool_type)() const; + typedef PyObject* (object::*bool_type)() const; template class object_operators { # if !defined(BOOST_MSVC) || BOOST_MSVC > 1200 - typedef object const& self_cref; + typedef object const& object_cref; # else - typedef object self_cref; + typedef object object_cref; # endif - // there appears to be a codegen bug here. We prevent the early - // destruction of a temporary in CWPro8 by binding a named - // object instead. + // there is a confirmed CWPro8 codegen bug here. We prevent the + // early destruction of a temporary by binding a named object + // instead. # if __MWERKS__ != 0x3000 - typedef object const& object_cref; + typedef object const& object_cref2; # else - typedef object const object_cref; + typedef object const object_cref2; # endif public: @@ -163,8 +138,8 @@ namespace api // item access // - const_object_item operator[](self_cref) const; - object_item operator[](self_cref); + const_object_item operator[](object_cref) const; + object_item operator[](object_cref); template const_object_item @@ -190,14 +165,14 @@ namespace api // slicing // - const_object_slice slice(self_cref, self_cref) const; - object_slice slice(self_cref, self_cref); + const_object_slice slice(object_cref, object_cref) const; + object_slice slice(object_cref, object_cref); - const_object_slice slice(slice_nil, self_cref) const; - object_slice slice(slice_nil, self_cref); + const_object_slice slice(slice_nil, object_cref) const; + object_slice slice(slice_nil, object_cref); - const_object_slice slice(self_cref, slice_nil) const; - object_slice slice(self_cref, slice_nil); + const_object_slice slice(object_cref, slice_nil) const; + object_slice slice(object_cref, slice_nil); # if !defined(BOOST_MSVC) || BOOST_MSVC > 1300 template @@ -227,53 +202,69 @@ namespace api , slice_bound::type(end)); } # endif - - -# if BOOST_MSVC == 1200 - // For whatever reason, VC6 generates incorrect code unless we - // define this - object_operators& operator=(object_operators const&) { return *this; } -# endif }; class object : public object_operators { public: # ifndef BOOST_NO_FUNCTION_TEMPLATE_ORDERING - // copy constructor without NULL checking, for efficiency + // copy constructor without NULL checking, for efficiency. This + // confuses VC6/7 so object_initializer also handles this case. object(object const&); # endif // explicit conversion from any C++ object to Python template explicit object(T const& x) - : m_ptr(object_handle::value>::get(x)) + : m_ptr(object_initializer::value>::get( + x, detail::convertible::check(&x))) { } - // capture this case explicitly to handle string - // literals. Otherwise, they get deduced as char[N]const& above - // and conversion fails at runtime. - explicit object(char const* x) - : m_ptr(object_handle<>::get(x)) - { - } - // Throw error_already_set() if the handle is null. explicit object(handle<> const&); - // Underlying object access - handle<> const& ptr() const; + // Underlying object access -- returns a borrowed reference + PyObject* ptr() const; public: // implementation detail -- for internal use only - object(null_ok >*); - object(detail::borrowed >*); - object(detail::borrowed*); - class new_pyobject_reference; - object(new_pyobject_reference*); + explicit object(detail::borrowed_reference); + explicit object(detail::new_reference); private: - handle<> m_ptr; + PyObject* m_ptr; + }; + + // + // object_initializer -- get the handle to construct the object with, + // based on whether T is a proxy or derived from object + // + template + struct object_initializer + { + static PyObject* + get(object const& x, detail::yes_convertible) + { + return python::incref(x.ptr()); + } + + template + static PyObject* + get(T const& x, detail::no_convertible) + { + return python::incref(converter::arg_to_python(x).get()); + } + }; + + template <> + struct object_initializer + { + template + static PyObject* + get(proxy const& x, detail::no_convertible) + { + return python::incref(x.operator object().ptr()); + } }; } using api::object; @@ -336,39 +327,32 @@ namespace converter // inline object::object(handle<> const& x) - : m_ptr(python::borrowed(x.get())) + : m_ptr(incref(expect_non_null(x.get()))) {} # ifndef BOOST_NO_FUNCTION_TEMPLATE_ORDERING // copy constructor without NULL checking, for efficiency inline object::object(object const& rhs) - : m_ptr(python::allow_null(python::borrowed(rhs.m_ptr.get()))) + : m_ptr(incref(rhs.m_ptr)) {} # endif -inline object::object(null_ok >* p) - : m_ptr(p) +inline object::object(detail::borrowed_reference p) + : m_ptr(incref((PyObject*)p)) {} -inline object::object(detail::borrowed >* p) - : m_ptr(p) + +inline object::object(detail::new_reference p) + : m_ptr(expect_non_null((PyObject*)p)) {} -inline object::object(detail::borrowed* p) - : m_ptr(p) -{} - -inline object::object(object::new_pyobject_reference* p) - : m_ptr((PyObject*)p) -{} - -inline handle<> const& object::ptr() const +inline PyObject* object::ptr() const { return m_ptr; } // -// Converter speciaization implementations +// Converter specialization implementations // inline arg_from_python::arg_from_python(PyObject*) {} @@ -380,7 +364,7 @@ inline bool arg_from_python::convertible() const inline object arg_from_python::operator()(PyObject* x) const { - return object(python::borrowed(python::allow_null(x))); + return object(detail::borrowed_reference(x)); } inline arg_from_python::arg_from_python(PyObject*) @@ -388,7 +372,7 @@ inline arg_from_python::arg_from_python(PyObject*) {} inline arg_from_python::arg_from_python(PyObject* x) - : m_result(python::allow_null(python::borrowed(x))) + : m_result(detail::borrowed_reference(x)) {} inline bool arg_from_python::convertible() const @@ -406,12 +390,12 @@ namespace converter inline object return_from_python::operator()(PyObject* x) const { - return object((object::new_pyobject_reference*)x); + return object(python::detail::new_reference(x)); } inline PyObject* get_managed_object(object const& x) { - return x.ptr().get(); + return x.ptr(); } } diff --git a/include/boost/python/object_items.hpp b/include/boost/python/object_items.hpp index e07a9e50..436a671f 100755 --- a/include/boost/python/object_items.hpp +++ b/include/boost/python/object_items.hpp @@ -29,17 +29,17 @@ struct item_policies : const_item_policies // template inline object_item -object_operators::operator[](self_cref key) +object_operators::operator[](object_cref key) { - object_cref x = *static_cast(this); + object_cref2 x = *static_cast(this); return object_item(x, key); } template inline const_object_item -object_operators::operator[](self_cref key) const +object_operators::operator[](object_cref key) const { - object_cref x = *static_cast(this); + object_cref2 x = *static_cast(this); return const_object_item(x, key); } diff --git a/include/boost/python/object_operators.hpp b/include/boost/python/object_operators.hpp index 266018a6..1ac6e426 100644 --- a/include/boost/python/object_operators.hpp +++ b/include/boost/python/object_operators.hpp @@ -14,7 +14,7 @@ template object object_operators::operator()() const { object const& f = *static_cast(this); - return call(f.ptr().get()); + return call(f.ptr()); } @@ -23,7 +23,7 @@ inline object_operators::operator bool_type() const { object const& x = *static_cast(this); - return PyObject_IsTrue(x.ptr().get()) ? &object::ptr : 0; + return PyObject_IsTrue(x.ptr()) ? &object::ptr : 0; } template @@ -31,7 +31,7 @@ inline bool object_operators::operator!() const { object const& x = *static_cast(this); - return !PyObject_IsTrue(x.ptr().get()); + return !PyObject_IsTrue(x.ptr()); } # define BOOST_PYTHON_COMPARE_OP(op, opid) \ @@ -39,7 +39,7 @@ template \ bool operator op(L const& l, R const& r) \ { \ return PyObject_RichCompareBool( \ - object(l).ptr().get(), object(r).ptr().get(), opid); \ + object(l).ptr(), object(r).ptr(), opid); \ } BOOST_PYTHON_COMPARE_OP(>, Py_GT) BOOST_PYTHON_COMPARE_OP(>=, Py_GE) diff --git a/include/boost/python/object_slices.hpp b/include/boost/python/object_slices.hpp index 3e61d2da..a4348efc 100644 --- a/include/boost/python/object_slices.hpp +++ b/include/boost/python/object_slices.hpp @@ -30,50 +30,50 @@ struct slice_policies : const_slice_policies // template object_slice -object_operators::slice(self_cref start, self_cref finish) +object_operators::slice(object_cref start, object_cref finish) { - object_cref x = *static_cast(this); - return object_slice(x, std::make_pair(start.ptr(), finish.ptr())); + object_cref2 x = *static_cast(this); + return object_slice(x, std::make_pair(borrowed(start.ptr()), borrowed(finish.ptr()))); } template const_object_slice -object_operators::slice(self_cref start, self_cref finish) const +object_operators::slice(object_cref start, object_cref finish) const { - object_cref x = *static_cast(this); - return const_object_slice(x, std::make_pair(start.ptr(), finish.ptr())); + object_cref2 x = *static_cast(this); + return const_object_slice(x, std::make_pair(borrowed(start.ptr()), borrowed(finish.ptr()))); } template object_slice -object_operators::slice(slice_nil, self_cref finish) +object_operators::slice(slice_nil, object_cref finish) { - object_cref x = *static_cast(this); - return object_slice(x, std::make_pair(handle<>(), finish.ptr())); + object_cref2 x = *static_cast(this); + return object_slice(x, std::make_pair(allow_null((PyObject*)0), borrowed(finish.ptr()))); } template const_object_slice -object_operators::slice(slice_nil, self_cref finish) const +object_operators::slice(slice_nil, object_cref finish) const { - object_cref x = *static_cast(this); - return const_object_slice(x, std::make_pair(handle<>(), finish.ptr())); + object_cref2 x = *static_cast(this); + return const_object_slice(x, std::make_pair(allow_null((PyObject*)0), borrowed(finish.ptr()))); } template object_slice -object_operators::slice(self_cref start, slice_nil) +object_operators::slice(object_cref start, slice_nil) { - object_cref x = *static_cast(this); - return object_slice(x, std::make_pair(start.ptr(), handle<>())); + object_cref2 x = *static_cast(this); + return object_slice(x, std::make_pair(borrowed(start.ptr()), allow_null((PyObject*)0))); } template const_object_slice -object_operators::slice(self_cref start, slice_nil) const +object_operators::slice(object_cref start, slice_nil) const { - object_cref x = *static_cast(this); - return const_object_slice(x, std::make_pair(start.ptr(), handle<>())); + object_cref2 x = *static_cast(this); + return const_object_slice(x, std::make_pair(borrowed(start.ptr()), allow_null((PyObject*)0))); } # if !defined(BOOST_MSVC) || BOOST_MSVC > 1300 template diff --git a/include/boost/python/objects.hpp b/include/boost/python/objects.hpp index a5b87d88..cab5f720 100644 --- a/include/boost/python/objects.hpp +++ b/include/boost/python/objects.hpp @@ -11,6 +11,7 @@ # ifdef BOOST_PYTHON_V2 # include +# include # else # include # include diff --git a/include/boost/python/objects2.hpp b/include/boost/python/objects2.hpp index 62d8c09f..a66a422e 100755 --- a/include/boost/python/objects2.hpp +++ b/include/boost/python/objects2.hpp @@ -14,6 +14,8 @@ namespace boost { namespace python { +class list; + class BOOST_PYTHON_DECL objects_base { public: @@ -97,67 +99,6 @@ class tuple : public tuple_base } }; -class list; - -struct BOOST_PYTHON_DECL list_proxy; -struct BOOST_PYTHON_DECL list_slice_proxy; - -class BOOST_PYTHON_DECL list_base : public objects_base -{ - protected: - typedef list_proxy proxy; - typedef list_slice_proxy slice_proxy; - public: - explicit list_base(handle<> p); - explicit list_base(std::size_t sz = 0); - static PyTypeObject* type_obj(); - static bool accepts(handle<> p); - std::size_t size() const; - handle<> operator[](std::size_t pos) const; - proxy operator[](std::size_t pos); - handle<> get_item(std::size_t pos) const; - - void set_item(std::size_t pos, const handle<>& ); - -// void set_item(std::size_t pos, const object& ); - - void insert(std::size_t index, const handle<>& item); - - void push_back(const handle<>& item); - - void append(const handle<>& item); - - list slice(int low, int high) const; - slice_proxy slice(int low, int high); - void sort(); - void reverse(); - tuple as_tuple() const; -}; - -class list : public list_base -{ - public: - explicit list(handle<> p) : list_base(p) {} - explicit list(std::size_t sz = 0) : list_base(sz) {} - template - void set_item(std::size_t pos, const T& x) - { this->set_item(pos, make_ref(x)); } - template - void insert(std::size_t index, const T& x) - { this->insert(index, make_ref(x)); } - template - void push_back(const T& item) - { this->push_back(make_ref(item)); } - template - void append(const T& item) - { this->append(make_ref(item)); } - - void set_item(std::size_t pos, const handle<>& x) { list_base::set_item(pos, x); } - void insert(std::size_t index, const handle<>& item) { list_base::insert(index, item); } - void push_back(const handle<>& item) { list_base::push_back(item); } - void append(const handle<>& item) { list_base::append(item); } -}; - class BOOST_PYTHON_DECL string : public objects_base, public boost::multipliable2 { @@ -306,43 +247,6 @@ class dictionary : public dictionary_base { dictionary_base::erase(key); } }; -struct BOOST_PYTHON_DECL list_proxy -{ - template - const handle<>& operator=(const T& rhs) - { return (*this) = make_ref(rhs); } - const handle<>& operator=(const handle<>& rhs); - - operator handle<>() const; - - private: - friend class list_base; - list_proxy(const handle<>& list, std::size_t index); - - // This is needed to work around the very strange MSVC error report that the - // return type of the built-in operator= differs from that of the ones - // defined above. Couldn't hurt to make these un-assignable anyway, though. - const handle<>& operator=(const list_proxy&); // Not actually implemented - private: - list m_list; - std::size_t m_index; -}; - -struct BOOST_PYTHON_DECL list_slice_proxy -{ - const list& operator=(const list& rhs); - operator handle<>() const; - operator list() const; - std::size_t size() const; - handle<> operator[](std::size_t pos) const; - private: - friend class list_base; - list_slice_proxy(const handle<>& list, int low, int high); - private: - handle<> m_list; - int m_low, m_high; -}; - }} // namespace boost::python #endif // OBJECTS_DWA20020611_H diff --git a/include/boost/python/proxy.hpp b/include/boost/python/proxy.hpp index 385d4b3d..2f06eeb9 100755 --- a/include/boost/python/proxy.hpp +++ b/include/boost/python/proxy.hpp @@ -73,10 +73,10 @@ inline proxy const& proxy::operator=(typename proxy::copy_ct # define BOOST_PYTHON_PROXY_INPLACE(op) \ template \ -proxy const& operator op(proxy const& lhs, R const& other) \ +proxy const& operator op(proxy const& lhs, R const& rhs) \ { \ object old(lhs); \ - return lhs = (old op other); \ + return lhs = (old op rhs); \ } BOOST_PYTHON_PROXY_INPLACE(+=) BOOST_PYTHON_PROXY_INPLACE(-=) diff --git a/src/list.cpp b/src/list.cpp new file mode 100644 index 00000000..7931c899 --- /dev/null +++ b/src/list.cpp @@ -0,0 +1,105 @@ +// Copyright David Abrahams 2002. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#include + +namespace boost { namespace python { + +BOOST_PYTHON_DECL detail::new_reference list::call(object const& arg) +{ + return (detail::new_reference)PyObject_CallFunction( + (PyObject*)&PyList_Type, "(O)", + arg.ptr()); +} + +BOOST_PYTHON_DECL list::list() + : object(detail::new_reference(PyList_New(0))) +{} + +BOOST_PYTHON_DECL list::list(object_cref sequence) + : object(list::call(sequence)) +{} + +BOOST_PYTHON_DECL void list::append(object_cref x) +{ + if (PyList_Append(this->ptr(), x.ptr()) == -1) + throw_error_already_set(); +} + +BOOST_PYTHON_DECL long list::count(object_cref value) const +{ + object result_obj(this->attr("count")(value)); + long result = PyInt_AsLong(result_obj.ptr()); + if (result == -1) + throw_error_already_set(); + return result; +} + +BOOST_PYTHON_DECL void list::extend(object_cref sequence) +{ + this->attr("extend")(sequence); +} + +BOOST_PYTHON_DECL long list::index(object_cref value) const +{ + object result_obj(this->attr("index")(value)); + long result = PyInt_AsLong(result_obj.ptr()); + if (result == -1) + throw_error_already_set(); + return result; +} + +BOOST_PYTHON_DECL void list::insert(int index, object_cref item) +{ + if (PyList_Insert(this->ptr(), index, item.ptr()) == -1) + throw_error_already_set(); +} + +BOOST_PYTHON_DECL void list::insert(object const& index, object_cref x) +{ + long index_ = PyInt_AsLong(index.ptr()); + if (index_ == -1 && PyErr_Occurred()) + throw_error_already_set(); + this->insert(index_, x); +} + +BOOST_PYTHON_DECL object list::pop() +{ + return this->attr("pop")(); +} + +BOOST_PYTHON_DECL object list::pop(long index) +{ + return this->pop(object(index)); +} + +BOOST_PYTHON_DECL object list::pop(object const& index) +{ + return this->attr("pop")(index); +} + +BOOST_PYTHON_DECL void list::remove(object_cref value) +{ + this->attr("remove")(value); +} + +BOOST_PYTHON_DECL void list::reverse() +{ + if (PyList_Reverse(this->ptr()) == -1) + throw_error_already_set(); +} + +BOOST_PYTHON_DECL void list::sort() +{ + if (PyList_Sort(this->ptr()) == -1) + throw_error_already_set(); +} + +BOOST_PYTHON_DECL void list::sort(object_cref cmpfunc) +{ + this->attr("sort")(cmpfunc); +} + +}} // namespace boost::python diff --git a/src/object/class.cpp b/src/object/class.cpp index a64b811d..3f03df64 100644 --- a/src/object/class.cpp +++ b/src/object/class.cpp @@ -5,7 +5,7 @@ // to its suitability for any purpose. #include #include -#include +#include #include #include #include @@ -210,7 +210,7 @@ namespace objects type_handle query(class_id id) const; void set(class_id, type_handle class_object); private: - typedef detail::map_entry entry; + typedef python::detail::map_entry entry; std::vector m_impl; }; diff --git a/src/object/function.cpp b/src/object/function.cpp index 8855ba75..4e237e4e 100644 --- a/src/object/function.cpp +++ b/src/object/function.cpp @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/object_operators.cpp b/src/object_operators.cpp index 0aa0f1b7..471f01ad 100644 --- a/src/object_operators.cpp +++ b/src/object_operators.cpp @@ -5,6 +5,7 @@ // to its suitability for any purpose. #include +#include namespace boost { namespace python { namespace api { @@ -12,8 +13,9 @@ namespace boost { namespace python { namespace api { BOOST_PYTHON_DECL object operator op(object const& l, object const& r) \ { \ return object( \ - (object::new_pyobject_reference*) \ - PyNumber_##name(l.ptr().get(), r.ptr().get())); \ + detail::new_reference( \ + PyNumber_##name(l.ptr(), r.ptr())) \ + ); \ } BOOST_PYTHON_BINARY_OPERATOR(+, Add) @@ -32,8 +34,8 @@ BOOST_PYTHON_BINARY_OPERATOR(|, Or) BOOST_PYTHON_DECL object& operator op##=(object& l, object const& r) \ { \ return l = object( \ - (object::new_pyobject_reference*) \ - PyNumber_InPlace##name(l.ptr().get(), r.ptr().get())); \ + (detail::new_reference) \ + PyNumber_InPlace##name(l.ptr(), r.ptr())); \ } BOOST_PYTHON_INPLACE_OPERATOR(+, Add) diff --git a/src/object_protocol.cpp b/src/object_protocol.cpp index abcb7994..cafb70f3 100755 --- a/src/object_protocol.cpp +++ b/src/object_protocol.cpp @@ -12,33 +12,33 @@ namespace boost { namespace python { namespace api { BOOST_PYTHON_DECL object getattr(object const& target, object const& key) { - return object((object::new_pyobject_reference*)PyObject_GetAttr(target.ptr().get(), key.ptr().get())); + return object(detail::new_reference(PyObject_GetAttr(target.ptr(), key.ptr()))); } BOOST_PYTHON_DECL void setattr(object const& target, object const& key, object const& value) { - if (PyObject_SetAttr(target.ptr().get(), key.ptr().get(), value.ptr().get()) == -1) + if (PyObject_SetAttr(target.ptr(), key.ptr(), value.ptr()) == -1) throw_error_already_set(); } BOOST_PYTHON_DECL void delattr(object const& target, object const& key) { - if (PyObject_DelAttr(target.ptr().get(), key.ptr().get()) == -1) + if (PyObject_DelAttr(target.ptr(), key.ptr()) == -1) throw_error_already_set(); } BOOST_PYTHON_DECL object getattr(object const& target, char const* key) { return object( - (object::new_pyobject_reference*) - PyObject_GetAttrString(target.ptr().get(), const_cast(key)) - ); + detail::new_reference( + PyObject_GetAttrString(target.ptr(), const_cast(key)) + )); } BOOST_PYTHON_DECL void setattr(object const& target, char const* key, object const& value) { if (PyObject_SetAttrString( - target.ptr().get(), const_cast(key), value.ptr().get()) == -1 + target.ptr(), const_cast(key), value.ptr()) == -1 ) { throw_error_already_set(); @@ -48,7 +48,7 @@ BOOST_PYTHON_DECL void setattr(object const& target, char const* key, object con BOOST_PYTHON_DECL void delattr(object const& target, char const* key) { if (PyObject_DelAttrString( - target.ptr().get(), const_cast(key)) == -1 + target.ptr(), const_cast(key)) == -1 ) { throw_error_already_set(); @@ -57,18 +57,19 @@ BOOST_PYTHON_DECL void delattr(object const& target, char const* key) BOOST_PYTHON_DECL object getitem(object const& target, object const& key) { - return object((object::new_pyobject_reference*)PyObject_GetItem(target.ptr().get(), key.ptr().get())); + return object(detail::new_reference( + PyObject_GetItem(target.ptr(), key.ptr()))); } BOOST_PYTHON_DECL void setitem(object const& target, object const& key, object const& value) { - if (PyObject_SetItem(target.ptr().get(), key.ptr().get(), value.ptr().get()) == -1) + if (PyObject_SetItem(target.ptr(), key.ptr(), value.ptr()) == -1) throw_error_already_set(); } BOOST_PYTHON_DECL void delitem(object const& target, object const& key) { - if (PyObject_DelItem(target.ptr().get(), key.ptr().get()) == -1) + if (PyObject_DelItem(target.ptr(), key.ptr()) == -1) throw_error_already_set(); } @@ -141,14 +142,14 @@ namespace // slicing code copied directly out of the Python implementation BOOST_PYTHON_DECL object getslice(object const& target, handle<> const& begin, handle<> const& end) { return object( - (object::new_pyobject_reference*) - apply_slice(target.ptr().get(), begin.get(), end.get())); + detail::new_reference( + apply_slice(target.ptr(), begin.get(), end.get()))); } BOOST_PYTHON_DECL void setslice(object const& target, handle<> const& begin, handle<> const& end, object const& value) { if (assign_slice( - target.ptr().get(), begin.get(), end.get(), value.ptr().get()) == -1 + target.ptr(), begin.get(), end.get(), value.ptr()) == -1 ) { throw_error_already_set(); @@ -158,7 +159,7 @@ BOOST_PYTHON_DECL void setslice(object const& target, handle<> const& begin, han BOOST_PYTHON_DECL void delslice(object const& target, handle<> const& begin, handle<> const& end) { if (assign_slice( - target.ptr().get(), begin.get(), end.get(), 0) == -1 + target.ptr(), begin.get(), end.get(), 0) == -1 ) { throw_error_already_set(); diff --git a/src/objects2.cpp b/src/objects2.cpp index 699b21df..462535e2 100755 --- a/src/objects2.cpp +++ b/src/objects2.cpp @@ -276,151 +276,4 @@ tuple operator+(const tuple& x, const tuple& y) return result; } - -list_base::list_base(handle<> p) - : objects_base(p) -{ - assert(accepts(p)); - if (!accepts(p)) - { - PyErr_SetString(PyExc_TypeError, p->ob_type->tp_name); - throw_error_already_set(); - } -} - -list_base::list_base(std::size_t sz) - : objects_base(handle<>(PyList_New(sz))) -{ -} - -PyTypeObject* list_base::type_obj() -{ - return &PyList_Type; -} - -bool list_base::accepts(handle<> p) -{ - return PyList_Check(p.get()); -} - -std::size_t list_base::size() const -{ - return PyList_Size(get()); -} - -handle<> list_base::operator[](std::size_t pos) const -{ - return handle<>(borrowed(PyList_GetItem(get(), pos))); -} - -list_proxy list_base::operator[](std::size_t pos) -{ - return proxy(reference(), pos); -} - -void list_base::insert(std::size_t index, const handle<>& item) -{ - if (PyList_Insert(get(), index, item.get()) == -1) - throw_error_already_set(); -} - -void list_base::push_back(const handle<>& item) -{ - if (PyList_Append(get(), item.get()) == -1) - throw_error_already_set(); -} - -void list_base::append(const handle<>& item) -{ - this->push_back(item); -} - -list list_base::slice(int low, int high) const -{ - return list(handle<>(PyList_GetSlice(get(), low, high))); -} - -list_slice_proxy list_base::slice(int low, int high) -{ - return list_slice_proxy(reference(), low, high); -} - -void list_base::sort() -{ - if (PyList_Sort(get()) == -1) - throw_error_already_set(); -} - -void list_base::reverse() -{ - if (PyList_Reverse(get()) == -1) - throw_error_already_set(); -} - -tuple list_base::as_tuple() const -{ - return tuple(handle<>(PyList_AsTuple(get()))); -} - -const handle<>& list_proxy::operator=(const handle<>& rhs) -{ - m_list.set_item(m_index, rhs); - return rhs; -} - -list_proxy::operator handle<>() const -{ - return handle<>(borrowed(PyList_GetItem(m_list.get(), m_index))); -} - -handle<> list_base::get_item(std::size_t pos) const -{ - return handle<>(borrowed(PyList_GetItem(this->get(), pos))); -} - -void list_base::set_item(std::size_t pos, const handle<>& rhs) -{ - int result = PyList_SetItem(this->get(), pos, rhs.get()); - if (result == -1) - throw_error_already_set(); - Py_INCREF(rhs.get()); -} - -list_proxy::list_proxy(const handle<>& list, std::size_t index) - : m_list(list), m_index(index) -{ -} - -const list& list_slice_proxy::operator=(const list& rhs) -{ - if (PyList_SetSlice(m_list.get(), m_low, m_high, rhs.get()) == -1) - throw_error_already_set(); - return rhs; -} - -list_slice_proxy::operator handle<>() const -{ - return handle<>(PyList_GetSlice(m_list.get(), m_low, m_high)); -} - -list_slice_proxy::operator list() const -{ - return list(this->operator handle<>()); -} - -std::size_t list_slice_proxy::size() const -{ - return this->operator list().size(); -} - -handle<> list_slice_proxy::operator[](std::size_t pos) const -{ - return this->operator list()[pos].operator handle<>(); -} - -list_slice_proxy::list_slice_proxy(const handle<>& list, int low, int high) - : m_list(list), m_low(low), m_high(high) -{ -} - }} // namespace boost::python diff --git a/test/Jamfile b/test/Jamfile index b54bb723..6fe1fc61 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -62,6 +62,7 @@ bpl-test test_pointer_adoption ; bpl-test operators ; bpl-test callbacks ; bpl-test object ; +bpl-test list ; bpl-test virtual_functions ; bpl-test back_reference ; bpl-test implicit ; @@ -88,6 +89,7 @@ run bases.cpp ; run if_else.cpp ; run pointee.cpp ; run result.cpp ; +compile string_literal.cpp ; compile borrowed.cpp : $(PYTHON_PROPERTIES) ; compile object_manager.cpp : $(PYTHON_PROPERTIES) ; diff --git a/test/list.cpp b/test/list.cpp new file mode 100644 index 00000000..714efc7e --- /dev/null +++ b/test/list.cpp @@ -0,0 +1,131 @@ +// Copyright David Abrahams 2002. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. + +#include +#include +#include +#include +#include +#include "test_class.hpp" + +using namespace boost::python; + +object new_list() +{ + return list(); +} + +list listify(object x) +{ + return list(x); +} + +object listify_string(char const* s) +{ + return list(s); +} + +std::string x_rep(test_class<> const& x) +{ + return "X(" + boost::lexical_cast(x.value()) + ")"; +} + +object apply_object_list(object f, list x) +{ + return f(x); +} + +void append_object(list& x, object y) +{ + x.append(y); +} + +void append_list(list& x, list const& y) +{ + x.append(y); +} + +typedef test_class<> X; + +int notcmp(object const& x, object const& y) +{ + return y < x ? -1 : y > x ? 1 : 0; +} + +void exercise(list x, object y, object print) +{ + x.append(y); + x.append(5); + x.append(X(3)); + + print("after append:"); + print(x); + + print("number of", y, "instances:", x.count(y)); + + print("number of 5s:", x.count(5)); + + x.extend("xyz"); + print("after extend:"); + print(x); + print("index of", y, "is:", x.index(y)); + print("index of 'l' is:", x.index("l")); + + x.insert(4, 666); + print("after inserting 666:"); + print(x); + print("inserting with object as index:"); + x.insert(x[x.index(5)], "---"); + print(x); + + print("popping..."); + x.pop(); + print(x); + x.pop(x[x.index(5)]); + print(x); + x.pop(x.index(5)); + print(x); + + print("removing", y); + x.remove(y); + print(x); + print("removing", 666); + x.remove(666); + print(x); + + print("reversing..."); + x.reverse(); + print(x); + + print("sorted:"); + x.pop(2); // make sorting predictable + x.sort(); + print(x); + + print("reverse sorted:"); + x.sort(handle<>(make_function(notcmp))); + print(x); +} + +BOOST_PYTHON_MODULE_INIT(list_ext) +{ + module("list_ext") + .def("new_list", new_list) + .def("listify", listify) + .def("listify_string", listify_string) + .def("apply_object_list", apply_object_list) + + .def("append_object", append_object) + .def("append_list", append_list) + + .def("exercise", exercise) + + .add(class_("X") + .def_init(args()) + .def( "__repr__", x_rep)) + ; +} +