Add peekref_method support, to solve an issue related to virtual methods, user classes, and reference counting.

This commit is contained in:
Gustavo J. A. M. Carneiro committed 2008-01-02 18:51:27 +00:00
1 parent 76c1e4e888
commit aae1dcfe7e
6 files changed
+102 -12

No files matched your search

+24
View File
@@ -174,3 +174,27 @@ template <> std::string TypeNameGet<int> (void)
{
return "int";
}
static Zbr *g_zbr = NULL;
int Zbr::instance_count = 0;
void store_zbr (Zbr *zbr)
{
if (g_zbr)
g_zbr->Unref ();
g_zbr = zbr;
}
int invoke_zbr (int x)
{
return g_zbr->get_int (x);
}
void delete_stored_zbr (void)
{
if (g_zbr)
g_zbr->Unref ();
g_zbr = NULL;
}
+20 -4
View File
@@ -91,21 +91,21 @@ public:
Foo* get_hidden_subclass_pointer ();
class Zbr
// -#- incref_method=Ref; decref_method=Unref -#-
// -#- incref_method=Ref; decref_method=Unref; peekref_method=GetReferenceCount -#-
{
int m_refcount;
std::string m_datum;
public:
Zbr () : m_refcount (1), m_datum ("")
{}
{ Zbr::instance_count++; }
Zbr (std::string datum) : m_refcount (1), m_datum (datum)
{}
{ Zbr::instance_count++; }
std::string get_datum () const { return m_datum; }
Zbr (Zbr const & other) :
m_refcount (1), m_datum (other.get_datum ())
{}
{Zbr::instance_count++;}
void Ref () {
// std::cerr << "Ref Zbr " << this << " from " << m_refcount << std::endl;
@@ -116,8 +116,24 @@ public:
if (--m_refcount == 0)
delete this;
}
int GetReferenceCount () const { return m_refcount; }
virtual int get_int (int x) {
return x;
}
static int instance_count;
virtual ~Zbr () {
--Zbr::instance_count;
}
};
// -#- @zbr(transfer_ownership=true) -#-
void store_zbr (Zbr *zbr);
int invoke_zbr (int x);
void delete_stored_zbr (void);
class Foobar
{
+11 -2
View File
@@ -90,13 +90,22 @@ def my_module_gen(out_file):
## Zbr is a reference counted class
Zbr = CppClass('Zbr', incref_method='Ref', decref_method='Unref')
Zbr = CppClass('Zbr', incref_method='Ref', decref_method='Unref',
peekref_method="GetReferenceCount", allow_subclassing=True)
mod.add_class(Zbr)
Zbr.add_constructor(
CppConstructor([Parameter.new('std::string', 'datum')]))
Zbr.add_method(CppMethod(ReturnValue.new('std::string'), 'get_datum', []))
Zbr.add_method(CppMethod(ReturnValue.new('int'), 'get_int', [Parameter.new('int', 'x')],
is_virtual=True))
Zbr.add_static_attribute(ReturnValue.new('int'), 'instance_count')
mod.add_function(Function(ReturnValue.new('void'), 'store_zbr',
[Parameter.new('Zbr*', 'zbr', transfer_ownership=True)]))
mod.add_function(Function(ReturnValue.new('int'), 'invoke_zbr',
[Parameter.new('int', 'x')]))
mod.add_function(Function(ReturnValue.new('void'), 'delete_stored_zbr', []))
mod.add_function(Function(ReturnValue.new('int'), 'print_something',
[Parameter.new('const char*', 'message')]))
+33 -3
View File
@@ -252,9 +252,7 @@ class TestFoo(unittest.TestCase):
while gc.collect():
pass
count_before = foo.SomeObject.instance_count
obj = Test("xxx", "yyy")
foo.store_some_object(obj)
del obj
foo.store_some_object(Test("xxx", "yyy"))
while gc.collect():
pass
@@ -612,5 +610,37 @@ class TestFoo(unittest.TestCase):
x = c.invoke_protected_virtual(2)
self.assertEqual(x, 9)
def test_subclass_with_reference_counting(self):
class Test(foo.Zbr):
def __init__(self, y):
super(Test, self).__init__("foo")
self.y = y
def _get_int(self, x):
return getattr(self, 'y', 0) + x
while gc.collect():
pass
count_before = foo.Zbr.instance_count
foo.store_zbr(Test(123))
while gc.collect():
pass
## check that Zbr isn't prematurely deleted
self.assertEqual(foo.Zbr.instance_count, count_before + 1)
## invoke the virtual method and check that it returns the correct value
value = foo.invoke_zbr(456)
self.assertEqual(value, 123+456)
## now delete the object from the C side..
foo.delete_stored_zbr()
while gc.collect():
pass
## check that Zbr was finally deleted
self.assertEqual(foo.Zbr.instance_count, count_before)
if __name__ == '__main__':
unittest.main()
+12 -3
View File
@@ -260,7 +260,8 @@ class CppClass(object):
def __init__(self, name, parent=None, incref_method=None, decref_method=None,
automatic_type_narrowing=None, allow_subclassing=None,
is_singleton=False, outer_class=None):
is_singleton=False, outer_class=None,
peekref_method=None):
"""Constructor
name -- class name
parent -- optional parent class wrapper
@@ -282,6 +283,8 @@ class CppClass(object):
is_singleton -- if True, the class is considered a singleton,
and so the python wrapper will never call the
C++ class destructor to free the value.
peekref_method -- if the class supports reference counting, the
name of the method that returns the current reference count.
"""
assert outer_class is None or isinstance(outer_class, CppClass)
self.outer_class = outer_class
@@ -318,9 +321,11 @@ class CppClass(object):
if incref_method is None and parent is not None:
self.incref_method = parent.incref_method
self.decref_method = parent.decref_method
self.peekref_method = parent.peekref_method
else:
self.incref_method = incref_method
self.decref_method = decref_method
self.peekref_method = peekref_method
if automatic_type_narrowing is None:
if parent is None:
@@ -962,10 +967,14 @@ static void
if self.helper_class is None:
visit_self = ''
else:
if self.peekref_method is None:
peekref_code = ''
else:
peekref_code = " && self->obj->%s() == 1" % self.peekref_method
visit_self = '''
if (self->obj && typeid(*self->obj) == typeid(%s))
if (self->obj && typeid(*self->obj) == typeid(%s)%s)
Py_VISIT(self);
''' % self.helper_class.name
''' % (self.helper_class.name, peekref_code)
code_sink.writeln(r'''
static int
+2
View File
@@ -480,6 +480,8 @@ class ModuleParser(object):
kwargs.setdefault('incref_method', value)
elif name == 'decref_method':
kwargs.setdefault('decref_method', value)
elif name == 'peekref_method':
kwargs.setdefault('peekref_method', value)
elif name == 'automatic_type_narrowing':
kwargs.setdefault('automatic_type_narrowing', annotations_scanner.parse_boolean(value))
else: