From 8cc9080d367448edc08d6c8725282d2d5c5d0657 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Sat, 2 Feb 2002 20:48:37 +0000 Subject: [PATCH] Initial pointer adoption tests Have instances actually dispose of their held C++ objects! [SVN r12652] --- Jamfile | 20 +++++++++-- src/object/class.cpp | 19 +++++++++- test/test_builtin_converters.cpp | 2 -- test/test_pointer_adoption.cpp | 61 ++++++++++++++++++++++++++++++++ test/test_pointer_adoption.py | 29 +++++++++++++++ 5 files changed, 126 insertions(+), 5 deletions(-) create mode 100644 test/test_pointer_adoption.cpp create mode 100644 test/test_pointer_adoption.py diff --git a/Jamfile b/Jamfile index fec34d51..e897b19f 100644 --- a/Jamfile +++ b/Jamfile @@ -29,17 +29,20 @@ PYTHON_PROPERTIES BOOST_PYTHON_SOURCE ; - extension m1 : test/m1.cpp bpl # BOOST_PYTHON_TRACE + # -------- general test ------- + extension m1 : test/m1.cpp bpl : : debug-python ; - extension m2 : test/m2.cpp bpl # BOOST_PYTHON_TRACE + extension m2 : test/m2.cpp bpl : : debug-python ; boost-python-runtest try : test/newtest.py m1 m2 : : debug-python ; + # ----------- builtin converters ----------- + extension builtin_converters_ext : test/test_builtin_converters.cpp bpl : : debug-python @@ -50,4 +53,17 @@ PYTHON_PROPERTIES : : debug-python ; + + # ----------- pointer adoption ----------- + + extension test_pointer_adoption_ext : test/test_pointer_adoption.cpp bpl + : + : debug-python + ; + + boost-python-runtest test_pointer_adoption : test/test_pointer_adoption.py + test_pointer_adoption_ext + : + : debug-python + ; } diff --git a/src/object/class.cpp b/src/object/class.cpp index 5d1ecf01..6a839fb2 100644 --- a/src/object/class.cpp +++ b/src/object/class.cpp @@ -81,6 +81,22 @@ BOOST_PYTHON_DECL ref class_metatype() return ref((PyObject*)&class_metatype_object, ref::increment_count); } +extern "C" +{ + static void instance_dealloc(PyObject* inst) + { + instance* kill_me = (instance*)inst; + + for (instance_holder* p = kill_me->objects, *next; p != 0; p = next) + { + next = p->next(); + delete p; + } + + inst->ob_type->tp_free(inst); + } +} + // Do we really need this? I'm beginning to think we don't! PyTypeObject class_type_object = { PyObject_HEAD_INIT(0) //&class_metatype_object) @@ -88,7 +104,7 @@ PyTypeObject class_type_object = { "Boost.Python.instance", sizeof(instance), 0, - 0, /* tp_dealloc */ + instance_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ @@ -206,6 +222,7 @@ namespace m_impl.insert( boost::detail::lower_bound(start, finish, id) , entry(id, object)); + converter::registry::class_object(id) = (PyTypeObject*)object.get(); } } diff --git a/test/test_builtin_converters.cpp b/test/test_builtin_converters.cpp index 6ffccdf9..7e21e046 100644 --- a/test/test_builtin_converters.cpp +++ b/test/test_builtin_converters.cpp @@ -5,8 +5,6 @@ // to its suitability for any purpose. #include #include -#include -#include template diff --git a/test/test_pointer_adoption.cpp b/test/test_pointer_adoption.cpp new file mode 100644 index 00000000..a49be5e8 --- /dev/null +++ b/test/test_pointer_adoption.cpp @@ -0,0 +1,61 @@ +// 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 + +using namespace boost::python; +using boost::mpl::type_list; + +int a_instances = 0; + +int num_a_instances() { return a_instances; } + +struct A +{ + A(std::string const& s) + : s(s) + { + ++a_instances; + } + + ~A() + { + --a_instances; + } + + std::string content() const + { + return s; + } + + std::string s; +}; + +A* create(std::string const& s) +{ + return new A(s); +} + +BOOST_PYTHON_MODULE_INIT(test_pointer_adoption_ext) +{ + boost::python::module("test_pointer_adoption_ext") + .def("num_a_instances", num_a_instances) + + // Specify the manage_new_object return policy to take + // ownership of create's result + .def("create", create, return_value_policy()) + + .add( + class_() + .def("content", &A::content) + ) + + ; +} + diff --git a/test/test_pointer_adoption.py b/test/test_pointer_adoption.py new file mode 100644 index 00000000..264d69ce --- /dev/null +++ b/test/test_pointer_adoption.py @@ -0,0 +1,29 @@ +""" +>>> from test_pointer_adoption_ext import * + +>>> num_a_instances() +0 + +>>> a = create('dynamically allocated') +>>> num_a_instances() +1 + +>>> a.content() +'dynamically allocated' + +>>> a = None +>>> num_a_instances() +0 +""" +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print "running..." + import sys + sys.exit(run()[0])