From 55e0ea52bdf009f273f26ea6be1b9c98f31896f8 Mon Sep 17 00:00:00 2001 From: Marcelo Matus Date: Thu, 22 Jan 2004 06:26:17 +0000 Subject: [PATCH] added refcount example using the old macro way and the proposed ref/unref features git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk@5667 626c5289-ae23-0410-ae9c-e8d60b6d4f22 --- .../test-suite/python/refcount_runme.py | 15 ++ SWIG/Examples/test-suite/refcount.h | 198 ++++++++++++++++++ SWIG/Examples/test-suite/refcount.i | 116 ++++++++++ .../test-suite/ruby/refcount_runme.rb | 10 + 4 files changed, 339 insertions(+) create mode 100644 SWIG/Examples/test-suite/python/refcount_runme.py create mode 100644 SWIG/Examples/test-suite/refcount.h create mode 100644 SWIG/Examples/test-suite/refcount.i create mode 100644 SWIG/Examples/test-suite/ruby/refcount_runme.rb diff --git a/SWIG/Examples/test-suite/python/refcount_runme.py b/SWIG/Examples/test-suite/python/refcount_runme.py new file mode 100644 index 000000000..d7c708774 --- /dev/null +++ b/SWIG/Examples/test-suite/python/refcount_runme.py @@ -0,0 +1,15 @@ +from refcount import * +# +# very innocent example +# + +a = A3() +b1 = B(a) +b2 = B.create(a) + + + +if a.ref_count() != 3: + print "This program will crash... now" + + diff --git a/SWIG/Examples/test-suite/refcount.h b/SWIG/Examples/test-suite/refcount.h new file mode 100644 index 000000000..d98194bfa --- /dev/null +++ b/SWIG/Examples/test-suite/refcount.h @@ -0,0 +1,198 @@ +#ifndef __test_suite_refcount_h__ +#define __test_suite_refcount_h__ + +struct RCObjBase { + /*! + Return the numbers of active references. + + \return The internal \c refCount value. + */ + int ref_count() const + { + return refCount; + } + + /*! + Add one reference. + + \return The reference counter value. + */ + int ref() const + { + return add_ref(); + } + + /*! + Delete one reference. If the refCount is zero, the + object is deleted. + + \return The reference counter value, which can be zero after + deletion. + */ + int unref() const + { + if (ref_count() == 0 || del_ref() == 0 ) + { + delete this; + return 0; + } + return ref_count(); + } + +protected: + RCObjBase(); + RCObjBase(const RCObjBase& ); + virtual ~RCObjBase() = 0; + +private: + + RCObjBase& operator=(const RCObjBase& ); + + friend class RCObj; + + int add_ref() const + { + return ++refCount; + } + + int del_ref() const + { + return --refCount; + } + + mutable int refCount; +}; + +struct RCObj : virtual RCObjBase { +protected: + RCObj() + { + } +}; + +/*! Reference an RCObj object + \return The input pointer \a r +*/ +template +inline +T* ref(T* r) +{ + return (r && r->ref() ) ? r : 0; +} + +/*! Unreference an RCObj object. + \return The input pointer \a r or nil if the object was deleted. +*/ +template +inline +T* unref(T* r) +{ + return ( r && r->unref() ) ? r : 0; +} + + + +RCObjBase::RCObjBase() + : refCount(0) +{ +} + + +RCObjBase::~RCObjBase() +{ +} + +RCObjBase::RCObjBase(const RCObjBase&) + : refCount(0) +{ +} + + +RCObjBase& RCObjBase::operator=(const RCObjBase&) +{ + return *this; +} + + +template +struct RCPtr { + typedef T* pointer_type; + typedef T& refernce_type; + typedef T value_type; + + RCPtr(); + RCPtr(T* realPtr); + RCPtr(const RCPtr& rhs); + + ~RCPtr(); + + RCPtr& operator=(const RCPtr& rhs); + + RCPtr& operator=(T* realPtr); + + T* operator->() { return pointee; } + T& operator*() { return *pointee; } + + const T* operator->() const { return pointee; } + const T& operator*() const { return *pointee; } + + operator T*() { return pointee; } + operator T&() { return *pointee; } + + operator const T*() const { return pointee; } + operator const T&() const { return *pointee; } + + T* get() { return pointee; } + T* get() const { return pointee; } + + +private: + T* pointee; +}; + + +template +inline +RCPtr::RCPtr() + : pointee(0) +{ +} + +template +inline +RCPtr::RCPtr(T* realPtr) + : pointee(realPtr) +{ + ref(pointee); +} + +template +inline +RCPtr::RCPtr(const RCPtr& rhs) + : pointee(rhs.pointee) +{ + ref(pointee); +} + +template +inline +RCPtr::~RCPtr() +{ + unref(pointee); +} + +template +inline +RCPtr& RCPtr::operator=(const RCPtr& rhs) +{ + if (pointee != rhs.pointee) { + unref(pointee); + pointee = rhs.pointee; + ref(pointee); + } + return *this; +} + + + +#endif //__test_suite_refcount_h__ diff --git a/SWIG/Examples/test-suite/refcount.i b/SWIG/Examples/test-suite/refcount.i new file mode 100644 index 000000000..f9e69e787 --- /dev/null +++ b/SWIG/Examples/test-suite/refcount.i @@ -0,0 +1,116 @@ +%module refcount + +#pragma SWIG nowarn=362 +%{ +#include +#include "refcount.h" +%} + +#if 1 +// +// the old macro way +// +%define RefCount(...) + %typemap(newfree) __VA_ARGS__* { $1->ref(); } + %newobject __VA_ARGS__::clone(); + %extend __VA_ARGS__ { ~__VA_ARGS__() { self->unref(); } } + %ignore __VA_ARGS__::~__VA_ARGS__(); +%enddef +// +// you need to apply the RefCount macro to all the RCObj derived +// classes. +// +RefCount(RCObj); +RefCount(A); +RefCount(A1); +RefCount(A2); +RefCount(A3); +RefCount(B); + +#else +// +// using the ref/unref features you can active the ref. counting +// for RCObj and all its descendents at once +// +%feature("refbase") RCObj "$this->ref();" +%feature("unrefbase") RCObj "$this->unref();" + +#endif + +%include "refcount.h" + +%newobject B::create(); +%newobject B::cloner(); + +%inline %{ + + struct A : RCObj + { + A() {} + + ~A() + { + // std::cout << "deleting a" << std::endl; + } + +#ifdef SWIGRUBY + // fix strange ruby + virtual derivation problem + using RCObjBase::ref_count; +#endif + }; + + struct A1 : A + { + protected: + A1() {} + }; + + struct A2 : A + { + }; + + struct A3 : A1, private A2 + { + }; + + struct B : RCObj + { + B(A* a) : _a(a) {} + + static B* create(A* a) + { + return new B(a); + } + + B* cloner() + { + return new B(_a); + } + + ~B() + { + // std::cout << "deleting b" << std::endl; + } + + private: + RCPtr _a; + }; + +%} + + +/* Other ref/unref uses: + +// deactive the refcounting for A1 +%feature("noref") A1; +%feature("nounref") A1; + +// deactive the refcounting for A2 and all its descendents +%feature("norefbase") A2; +%feature("nounrefbase") A2; + +// active the refcounting only for A3 +%feature("ref") A3 { $this->ref(); } +%feature("unref") A3 { $this->unref(); } + +*/ diff --git a/SWIG/Examples/test-suite/ruby/refcount_runme.rb b/SWIG/Examples/test-suite/ruby/refcount_runme.rb new file mode 100644 index 000000000..a4fd74c85 --- /dev/null +++ b/SWIG/Examples/test-suite/ruby/refcount_runme.rb @@ -0,0 +1,10 @@ +require 'refcount' + + +a = Refcount::A3.new; +b1 = Refcount::B.new a; +b2 = Refcount::B.new a; + +if a.ref_count() != 3 + print "This program will crash... now\n" +end