From 595797b2902bfe7ad4699207d82d2fda22243f5e Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Thu, 16 Nov 2000 17:06:37 +0000 Subject: [PATCH] Handled some reference-counting problems and added some sequence points for exception-safety [SVN r8227] --- callback.h | 384 +++++++++++++++++++++++++++++------------------- gen_callback.py | 79 ++++++---- 2 files changed, 285 insertions(+), 178 deletions(-) diff --git a/callback.h b/callback.h index a47b173a..88ffe918 100644 --- a/callback.h +++ b/callback.h @@ -16,8 +16,13 @@ namespace py { -// Just like the above, except we decrement p's reference count instead of returning it. -void expect_and_absorb_non_null(PyObject* p); +namespace detail { + template + inline void callback_adjust_refcount(PyObject*, Type) {} + + inline void callback_adjust_refcount(PyObject* p, Type) + { Py_INCREF(p); } +} // Calling Python from C++ template @@ -25,110 +30,163 @@ struct Callback { static R call_method(PyObject* self, const char* name) { - return from_python(expect_non_null(PyEval_CallMethod(self, const_cast(name), - const_cast("()"))), Type()); + Ptr result(PyEval_CallMethod(self, const_cast(name), + const_cast("()"))); + detail::callback_adjust_refcount(result.get(), Type()); + return from_python(result.get(), Type()); + } + + static R call(PyObject* self) + { + Ptr result(PyEval_CallFunction(self, const_cast("()"))); + detail::callback_adjust_refcount(result.get(), Type()); + return from_python(result.get(), Type()); } template static R call_method(PyObject* self, const char* name, const A1& a1) { - return from_python(expect_non_null(PyEval_CallMethod(self, const_cast(name), - const_cast("(N)"), - to_python(a1))), Type()); - } - - template - static R call_method(PyObject* self, const char* name, const A1& a1, const A2& a2) - { - return from_python(expect_non_null(PyEval_CallMethod(self, const_cast(name), - const_cast("(NN)"), - to_python(a1), - to_python(a2))), Type()); - } - - template - static R call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3) - { - return from_python(expect_non_null(PyEval_CallMethod(self, const_cast(name), - const_cast("(NNN)"), - to_python(a1), - to_python(a2), - to_python(a3))), Type()); - } - - template - static R call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3, const A4& a4) - { - return from_python(expect_non_null(PyEval_CallMethod(self, const_cast(name), - const_cast("(NNNN)"), - to_python(a1), - to_python(a2), - to_python(a3), - to_python(a4))), Type()); - } - - template - static R call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5) - { - return from_python(expect_non_null(PyEval_CallMethod(self, const_cast(name), - const_cast("(NNNNN)"), - to_python(a1), - to_python(a2), - to_python(a3), - to_python(a4), - to_python(a5))), Type()); - } - - static R call(PyObject* self) - { - return from_python(expect_non_null(PyEval_CallFunction(self, const_cast("()"))), Type()); + Ptr p1(to_python(a1)); + Ptr result(PyEval_CallMethod(self, const_cast(name), + const_cast("(O)"), + p1.get())); + detail::callback_adjust_refcount(result.get(), Type()); + return from_python(result.get(), Type()); } template static R call(PyObject* self, const A1& a1) { - return from_python(expect_non_null(PyEval_CallFunction(self, const_cast("(N)"), - to_python(a1))), Type()); + Ptr p1(to_python(a1)); + Ptr result(PyEval_CallFunction(self, const_cast("(O)"), + p1.get())); + detail::callback_adjust_refcount(result.get(), Type()); + return from_python(result.get(), Type()); + } + + template + static R call_method(PyObject* self, const char* name, const A1& a1, const A2& a2) + { + Ptr p1(to_python(a1)); + Ptr p2(to_python(a2)); + Ptr result(PyEval_CallMethod(self, const_cast(name), + const_cast("(OO)"), + p1.get(), + p2.get())); + detail::callback_adjust_refcount(result.get(), Type()); + return from_python(result.get(), Type()); } template static R call(PyObject* self, const A1& a1, const A2& a2) { - return from_python(expect_non_null(PyEval_CallFunction(self, const_cast("(NN)"), - to_python(a1), - to_python(a2))), Type()); + Ptr p1(to_python(a1)); + Ptr p2(to_python(a2)); + Ptr result(PyEval_CallFunction(self, const_cast("(OO)"), + p1.get(), + p2.get())); + detail::callback_adjust_refcount(result.get(), Type()); + return from_python(result.get(), Type()); + } + + template + static R call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3) + { + Ptr p1(to_python(a1)); + Ptr p2(to_python(a2)); + Ptr p3(to_python(a3)); + Ptr result(PyEval_CallMethod(self, const_cast(name), + const_cast("(OOO)"), + p1.get(), + p2.get(), + p3.get())); + detail::callback_adjust_refcount(result.get(), Type()); + return from_python(result.get(), Type()); } template static R call(PyObject* self, const A1& a1, const A2& a2, const A3& a3) { - return from_python(expect_non_null(PyEval_CallFunction(self, const_cast("(NNN)"), - to_python(a1), - to_python(a2), - to_python(a3))), Type()); + Ptr p1(to_python(a1)); + Ptr p2(to_python(a2)); + Ptr p3(to_python(a3)); + Ptr result(PyEval_CallFunction(self, const_cast("(OOO)"), + p1.get(), + p2.get(), + p3.get())); + detail::callback_adjust_refcount(result.get(), Type()); + return from_python(result.get(), Type()); + } + + template + static R call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3, const A4& a4) + { + Ptr p1(to_python(a1)); + Ptr p2(to_python(a2)); + Ptr p3(to_python(a3)); + Ptr p4(to_python(a4)); + Ptr result(PyEval_CallMethod(self, const_cast(name), + const_cast("(OOOO)"), + p1.get(), + p2.get(), + p3.get(), + p4.get())); + detail::callback_adjust_refcount(result.get(), Type()); + return from_python(result.get(), Type()); } template static R call(PyObject* self, const A1& a1, const A2& a2, const A3& a3, const A4& a4) { - return from_python(expect_non_null(PyEval_CallFunction(self, const_cast("(NNNN)"), - to_python(a1), - to_python(a2), - to_python(a3), - to_python(a4))), Type()); + Ptr p1(to_python(a1)); + Ptr p2(to_python(a2)); + Ptr p3(to_python(a3)); + Ptr p4(to_python(a4)); + Ptr result(PyEval_CallFunction(self, const_cast("(OOOO)"), + p1.get(), + p2.get(), + p3.get(), + p4.get())); + detail::callback_adjust_refcount(result.get(), Type()); + return from_python(result.get(), Type()); + } + + template + static R call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5) + { + Ptr p1(to_python(a1)); + Ptr p2(to_python(a2)); + Ptr p3(to_python(a3)); + Ptr p4(to_python(a4)); + Ptr p5(to_python(a5)); + Ptr result(PyEval_CallMethod(self, const_cast(name), + const_cast("(OOOOO)"), + p1.get(), + p2.get(), + p3.get(), + p4.get(), + p5.get())); + detail::callback_adjust_refcount(result.get(), Type()); + return from_python(result.get(), Type()); } template static R call(PyObject* self, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5) { - return from_python(expect_non_null(PyEval_CallFunction(self, const_cast("(NNNNN)"), - to_python(a1), - to_python(a2), - to_python(a3), - to_python(a4), - to_python(a5))), Type()); + Ptr p1(to_python(a1)); + Ptr p2(to_python(a2)); + Ptr p3(to_python(a3)); + Ptr p4(to_python(a4)); + Ptr p5(to_python(a5)); + Ptr result(PyEval_CallFunction(self, const_cast("(OOOOO)"), + p1.get(), + p2.get(), + p3.get(), + p4.get(), + p5.get())); + detail::callback_adjust_refcount(result.get(), Type()); + return from_python(result.get(), Type()); } - }; // This specialization wouldn't be needed, but MSVC6 doesn't correctly allow the following: @@ -137,112 +195,142 @@ struct Callback template <> struct Callback { + static void call_method(PyObject* self, const char* name) { - expect_and_absorb_non_null(PyEval_CallMethod(self, const_cast(name), - const_cast("()"))); + Ptr result(PyEval_CallMethod(self, const_cast(name), + const_cast("()"))); + } + + static void call(PyObject* self) + { + Ptr result(PyEval_CallFunction(self, const_cast("()"))); } template static void call_method(PyObject* self, const char* name, const A1& a1) { - expect_and_absorb_non_null(PyEval_CallMethod(self, const_cast(name), - const_cast("(N)"), - to_python(a1))); - } - - template - static void call_method(PyObject* self, const char* name, const A1& a1, const A2& a2) - { - expect_and_absorb_non_null(PyEval_CallMethod(self, const_cast(name), - const_cast("(NN)"), - to_python(a1), - to_python(a2))); - } - - template - static void call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3) - { - expect_and_absorb_non_null(PyEval_CallMethod(self, const_cast(name), - const_cast("(NNN)"), - to_python(a1), - to_python(a2), - to_python(a3))); - } - - template - static void call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3, const A4& a4) - { - expect_and_absorb_non_null(PyEval_CallMethod(self, const_cast(name), - const_cast("(NNNN)"), - to_python(a1), - to_python(a2), - to_python(a3), - to_python(a4))); - } - - template - static void call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5) - { - expect_and_absorb_non_null(PyEval_CallMethod(self, const_cast(name), - const_cast("(NNNNN)"), - to_python(a1), - to_python(a2), - to_python(a3), - to_python(a4), - to_python(a5))); - } - - static void call(PyObject* self) - { - expect_and_absorb_non_null(PyEval_CallFunction(self, const_cast("()"))); + Ptr p1(to_python(a1)); + Ptr result(PyEval_CallMethod(self, const_cast(name), + const_cast("(O)"), + p1.get())); } template static void call(PyObject* self, const A1& a1) { - expect_and_absorb_non_null(PyEval_CallFunction(self, const_cast("(N)"), - to_python(a1))); + Ptr p1(to_python(a1)); + Ptr result(PyEval_CallFunction(self, const_cast("(O)"), + p1.get())); + } + + template + static void call_method(PyObject* self, const char* name, const A1& a1, const A2& a2) + { + Ptr p1(to_python(a1)); + Ptr p2(to_python(a2)); + Ptr result(PyEval_CallMethod(self, const_cast(name), + const_cast("(OO)"), + p1.get(), + p2.get())); } template static void call(PyObject* self, const A1& a1, const A2& a2) { - expect_and_absorb_non_null(PyEval_CallFunction(self, const_cast("(NN)"), - to_python(a1), - to_python(a2))); + Ptr p1(to_python(a1)); + Ptr p2(to_python(a2)); + Ptr result(PyEval_CallFunction(self, const_cast("(OO)"), + p1.get(), + p2.get())); + } + + template + static void call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3) + { + Ptr p1(to_python(a1)); + Ptr p2(to_python(a2)); + Ptr p3(to_python(a3)); + Ptr result(PyEval_CallMethod(self, const_cast(name), + const_cast("(OOO)"), + p1.get(), + p2.get(), + p3.get())); } template static void call(PyObject* self, const A1& a1, const A2& a2, const A3& a3) { - expect_and_absorb_non_null(PyEval_CallFunction(self, const_cast("(NNN)"), - to_python(a1), - to_python(a2), - to_python(a3))); + Ptr p1(to_python(a1)); + Ptr p2(to_python(a2)); + Ptr p3(to_python(a3)); + Ptr result(PyEval_CallFunction(self, const_cast("(OOO)"), + p1.get(), + p2.get(), + p3.get())); + } + + template + static void call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3, const A4& a4) + { + Ptr p1(to_python(a1)); + Ptr p2(to_python(a2)); + Ptr p3(to_python(a3)); + Ptr p4(to_python(a4)); + Ptr result(PyEval_CallMethod(self, const_cast(name), + const_cast("(OOOO)"), + p1.get(), + p2.get(), + p3.get(), + p4.get())); } template static void call(PyObject* self, const A1& a1, const A2& a2, const A3& a3, const A4& a4) { - expect_and_absorb_non_null(PyEval_CallFunction(self, const_cast("(NNNN)"), - to_python(a1), - to_python(a2), - to_python(a3), - to_python(a4))); + Ptr p1(to_python(a1)); + Ptr p2(to_python(a2)); + Ptr p3(to_python(a3)); + Ptr p4(to_python(a4)); + Ptr result(PyEval_CallFunction(self, const_cast("(OOOO)"), + p1.get(), + p2.get(), + p3.get(), + p4.get())); + } + + template + static void call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5) + { + Ptr p1(to_python(a1)); + Ptr p2(to_python(a2)); + Ptr p3(to_python(a3)); + Ptr p4(to_python(a4)); + Ptr p5(to_python(a5)); + Ptr result(PyEval_CallMethod(self, const_cast(name), + const_cast("(OOOOO)"), + p1.get(), + p2.get(), + p3.get(), + p4.get(), + p5.get())); } template static void call(PyObject* self, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5) { - expect_and_absorb_non_null(PyEval_CallFunction(self, const_cast("(NNNNN)"), - to_python(a1), - to_python(a2), - to_python(a3), - to_python(a4), - to_python(a5))); + Ptr p1(to_python(a1)); + Ptr p2(to_python(a2)); + Ptr p3(to_python(a3)); + Ptr p4(to_python(a4)); + Ptr p5(to_python(a5)); + Ptr result(PyEval_CallFunction(self, const_cast("(OOOOO)"), + p1.get(), + p2.get(), + p3.get(), + p4.get(), + p5.get())); } - }; } // namespace py diff --git a/gen_callback.py b/gen_callback.py index c63a5f49..c9d7a408 100644 --- a/gen_callback.py +++ b/gen_callback.py @@ -2,28 +2,6 @@ from gen_function import * import string def gen_callback(args): - # A template for the call_method function which we're going to generate - call_method = '''%{ template <%(class A%n%:, %)> -%} static %1 call_method(PyObject* self, const char* name%(, const A%n& a%n%)) - { - %2PyEval_CallMethod(self, const_cast(name), - const_cast("(%(N%))")%(, - to_python(a%n)%))%3; - } - -''' - - call_function = '''%{ template <%(class A%n%:, %)> -%} static %1 call(PyObject* self%(, const A%n& a%n%)) - { - %2PyEval_CallFunction(self, const_cast("(%(N%))")%(, - to_python(a%n)%))%3; - } - -''' - non_void = ('R', 'return from_python(expect_non_null(', '), Type())') - void = ('void', 'expect_and_absorb_non_null(', ')') - return ( """// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and // distribute this software is granted provided this copyright notice appears @@ -43,16 +21,41 @@ def gen_callback(args): namespace py { -// Just like the above, except we decrement p's reference count instead of returning it. -void expect_and_absorb_non_null(PyObject* p); +namespace detail { + template + inline void callback_adjust_refcount(PyObject*, Type) {} + + inline void callback_adjust_refcount(PyObject* p, Type) + { Py_INCREF(p); } +} // Calling Python from C++ template struct Callback -{ -""" % args - + gen_functions(call_method, args, 'R', 'return from_python(expect_non_null(', '), Type())') - + gen_functions(call_function, args, 'R', 'return from_python(expect_non_null(', '), Type())') +{""" % args + + + gen_functions(''' +%{ template <%(class A%n%:, %)> +%} static R call_method(PyObject* self, const char* name%(, const A%n& a%n%)) + {%( + Ptr p%n(to_python(a%n));%) + Ptr result(PyEval_CallMethod(self, const_cast(name), + const_cast("(%(O%))")%(, + p%n.get()%))); + detail::callback_adjust_refcount(result.get(), Type()); + return from_python(result.get(), Type()); + } + +%{ template <%(class A%n%:, %)> +%} static R call(PyObject* self%(, const A%n& a%n%)) + {%( + Ptr p%n(to_python(a%n));%) + Ptr result(PyEval_CallFunction(self, const_cast("(%(O%))")%(, + p%n.get()%))); + detail::callback_adjust_refcount(result.get(), Type()); + return from_python(result.get(), Type()); + } +''', args) + """}; @@ -63,8 +66,24 @@ template <> struct Callback { """ - + gen_functions(call_method, args, 'void', 'expect_and_absorb_non_null(', ')') - + gen_functions(call_function, args, 'void', 'expect_and_absorb_non_null(', ')') + + gen_functions(''' +%{ template <%(class A%n%:, %)> +%} static void call_method(PyObject* self, const char* name%(, const A%n& a%n%)) + {%( + Ptr p%n(to_python(a%n));%) + Ptr result(PyEval_CallMethod(self, const_cast(name), + const_cast("(%(O%))")%(, + p%n.get()%))); + } + +%{ template <%(class A%n%:, %)> +%} static void call(PyObject* self%(, const A%n& a%n%)) + {%( + Ptr p%n(to_python(a%n));%) + Ptr result(PyEval_CallFunction(self, const_cast("(%(O%))")%(, + p%n.get()%))); + } +''', args) + """};