mirror of https://github.com/KLayout/klayout.git
Fixed #33 (Plugin factory not working when using with Python)
The fix consisted of introducing "factory" type virtual methods which ensure that a reference is held to the returned object. This is important for implementing factory methods in Python. Without this, the object get destroyed before we have a chance to increment the reference count.
This commit is contained in:
parent
11c9d37e93
commit
1cea7dfd23
|
|
@ -364,7 +364,7 @@ private:
|
||||||
_ARGSPECMEM
|
_ARGSPECMEM
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class R _COMMA _TMPLARG>
|
template <class R _COMMA _TMPLARG, class F = gsi::return_by_value>
|
||||||
class _NAME(StaticMethod)
|
class _NAME(StaticMethod)
|
||||||
: public StaticMethodBase
|
: public StaticMethodBase
|
||||||
{
|
{
|
||||||
|
|
@ -384,7 +384,11 @@ public:
|
||||||
{
|
{
|
||||||
this->clear ();
|
this->clear ();
|
||||||
_ADDARGS
|
_ADDARGS
|
||||||
this->template set_return<R> ();
|
if (tl::value_from_type (typename F::is_factory ())) {
|
||||||
|
this->template set_return_new<R> ();
|
||||||
|
} else {
|
||||||
|
this->template set_return<R> ();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual MethodBase *clone () const
|
virtual MethodBase *clone () const
|
||||||
|
|
@ -408,50 +412,6 @@ private:
|
||||||
_ARGSPECMEM
|
_ARGSPECMEM
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class X _COMMA _TMPLARG>
|
|
||||||
class _NAME(Constructor)
|
|
||||||
: public StaticMethodBase
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
_NAME(Constructor) (const std::string &name, X *(*m) (_FUNCARGLIST), const std::string &doc)
|
|
||||||
: StaticMethodBase (name, doc), m_m (m)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
_NAME(Constructor) *add_args (_ARGSPEC)
|
|
||||||
{
|
|
||||||
_ARGSPECINIT;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
void initialize ()
|
|
||||||
{
|
|
||||||
this->clear ();
|
|
||||||
_ADDARGS
|
|
||||||
this->template set_return_new<X *> ();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual MethodBase *clone () const
|
|
||||||
{
|
|
||||||
return new _NAME(Constructor) (*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if _COUNT != 0
|
|
||||||
virtual void call (void *, SerialArgs &args, SerialArgs &ret) const
|
|
||||||
#else
|
|
||||||
virtual void call (void *, SerialArgs &, SerialArgs &ret) const
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
this->mark_called ();
|
|
||||||
_GETARGVARS;
|
|
||||||
ret.write<X *> ((*m_m) (_ARGVARLIST));
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
X *(*m_m) (_FUNCARGLIST);
|
|
||||||
_ARGSPECMEM
|
|
||||||
};
|
|
||||||
|
|
||||||
// pointer iterator method descriptors
|
// pointer iterator method descriptors
|
||||||
|
|
||||||
template <class X, class R _COMMA _TMPLARG>
|
template <class X, class R _COMMA _TMPLARG>
|
||||||
|
|
@ -1352,6 +1312,22 @@ method (const std::string &name, R (X::*m) (_FUNCARGLIST) _COMMA _ARGSPECS, cons
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
template <class X, class R _COMMA _TMPLARG>
|
||||||
|
Methods
|
||||||
|
factory (const std::string &name, R *(X::*m) (_FUNCARGLIST), const std::string &doc = std::string ())
|
||||||
|
{
|
||||||
|
return Methods (new _NAME(Method) <X, R * _COMMA _FUNCARGLIST, gsi::return_new_object> (name, m, doc));
|
||||||
|
}
|
||||||
|
|
||||||
|
#if _COUNT != 0
|
||||||
|
template <class X, class R _COMMA _TMPLARG _COMMA _TMPLARGSPECS>
|
||||||
|
Methods
|
||||||
|
factory (const std::string &name, R *(X::*m) (_FUNCARGLIST) _COMMA _ARGSPECS, const std::string &doc = std::string ())
|
||||||
|
{
|
||||||
|
return Methods ((new _NAME(Method) <X, R * _COMMA _FUNCARGLIST, gsi::return_new_object> (name, m, doc))->add_args (_ARGSPECARGS));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
template <class X, class R _COMMA _TMPLARG>
|
template <class X, class R _COMMA _TMPLARG>
|
||||||
Methods
|
Methods
|
||||||
method_ext (const std::string &name, R (*xm) (X * _COMMA _FUNCARGLIST), const std::string &doc = std::string ())
|
method_ext (const std::string &name, R (*xm) (X * _COMMA _FUNCARGLIST), const std::string &doc = std::string ())
|
||||||
|
|
@ -1388,7 +1364,7 @@ template <class X _COMMA _TMPLARG>
|
||||||
Methods
|
Methods
|
||||||
constructor (const std::string &name, X *(*m) (_FUNCARGLIST), const std::string &doc = std::string ())
|
constructor (const std::string &name, X *(*m) (_FUNCARGLIST), const std::string &doc = std::string ())
|
||||||
{
|
{
|
||||||
return Methods (new _NAME(Constructor) <X _COMMA _FUNCARGLIST> (name, m, doc));
|
return Methods (new _NAME(StaticMethod) <X * _COMMA _FUNCARGLIST, gsi::return_new_object> (name, m, doc));
|
||||||
}
|
}
|
||||||
|
|
||||||
#if _COUNT != 0
|
#if _COUNT != 0
|
||||||
|
|
@ -1396,7 +1372,7 @@ template <class X _COMMA _TMPLARG _COMMA _TMPLARGSPECS>
|
||||||
Methods
|
Methods
|
||||||
constructor (const std::string &name, X *(*m) (_FUNCARGLIST) _COMMA _ARGSPECS, const std::string &doc = std::string ())
|
constructor (const std::string &name, X *(*m) (_FUNCARGLIST) _COMMA _ARGSPECS, const std::string &doc = std::string ())
|
||||||
{
|
{
|
||||||
return Methods ((new _NAME(Constructor) <X _COMMA _FUNCARGLIST> (name, m, doc))->add_args (_ARGSPECARGS));
|
return Methods ((new _NAME(StaticMethod) <X * _COMMA _FUNCARGLIST, gsi::return_new_object> (name, m, doc))->add_args (_ARGSPECARGS));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
@ -1416,6 +1392,22 @@ method (const std::string &name, R (*m) (_FUNCARGLIST) _COMMA _ARGSPECS, const s
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
template <class R _COMMA _TMPLARG>
|
||||||
|
Methods
|
||||||
|
factory (const std::string &name, R *(*m) (_FUNCARGLIST), const std::string &doc = std::string ())
|
||||||
|
{
|
||||||
|
return Methods (new _NAME(StaticMethod) <R * _COMMA _FUNCARGLIST, gsi::return_new_object> (name, m, doc));
|
||||||
|
}
|
||||||
|
|
||||||
|
#if _COUNT != 0
|
||||||
|
template <class R _COMMA _TMPLARG _COMMA _TMPLARGSPECS>
|
||||||
|
Methods
|
||||||
|
factory (const std::string &name, R *(*m) (_FUNCARGLIST) _COMMA _ARGSPECS, const std::string &doc = std::string ())
|
||||||
|
{
|
||||||
|
return Methods ((new _NAME(StaticMethod) <R * _COMMA _FUNCARGLIST, gsi::return_new_object> (name, m, doc))->add_args (_ARGSPECARGS));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
template <class X, class R _COMMA _TMPLARG>
|
template <class X, class R _COMMA _TMPLARG>
|
||||||
Methods
|
Methods
|
||||||
callback (const std::string &name, R (X::*m) (_FUNCARGLIST), Callback X::*cb, const std::string &doc = std::string ())
|
callback (const std::string &name, R (X::*m) (_FUNCARGLIST), Callback X::*cb, const std::string &doc = std::string ())
|
||||||
|
|
@ -1432,6 +1424,22 @@ callback (const std::string &name, R (X::*m) (_FUNCARGLIST), Callback X::*cb _CO
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
template <class X, class R _COMMA _TMPLARG>
|
||||||
|
Methods
|
||||||
|
factory_callback (const std::string &name, R (X::*m) (_FUNCARGLIST), Callback X::*cb, const std::string &doc = std::string ())
|
||||||
|
{
|
||||||
|
return Methods (new _NAME(Method) <X, R _COMMA _FUNCARGLIST, gsi::return_new_object> (name, m, doc, cb));
|
||||||
|
}
|
||||||
|
|
||||||
|
#if _COUNT != 0
|
||||||
|
template <class X, class R _COMMA _TMPLARG _COMMA _TMPLARGSPECS>
|
||||||
|
Methods
|
||||||
|
factory_callback (const std::string &name, R (X::*m) (_FUNCARGLIST), Callback X::*cb _COMMA _ARGSPECS, const std::string &doc = std::string ())
|
||||||
|
{
|
||||||
|
return Methods ((new _NAME(Method) <X, R _COMMA _FUNCARGLIST, gsi::return_new_object> (name, m, doc, cb))->add_args (_ARGSPECARGS));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
template <class X, class R _COMMA _TMPLARG>
|
template <class X, class R _COMMA _TMPLARG>
|
||||||
Methods
|
Methods
|
||||||
method (const std::string &name, R (X::*m) (_FUNCARGLIST) const, const std::string &doc = std::string ())
|
method (const std::string &name, R (X::*m) (_FUNCARGLIST) const, const std::string &doc = std::string ())
|
||||||
|
|
@ -1480,6 +1488,22 @@ callback (const std::string &name, R (X::*m) (_FUNCARGLIST) const, Callback X::*
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
template <class X, class R _COMMA _TMPLARG>
|
||||||
|
Methods
|
||||||
|
factory_callback (const std::string &name, R (X::*m) (_FUNCARGLIST) const, Callback X::*cb, const std::string &doc = std::string ())
|
||||||
|
{
|
||||||
|
return Methods (new _NAME(ConstMethod) <X, R _COMMA _FUNCARGLIST, gsi::return_new_object> (name, m, doc, cb));
|
||||||
|
}
|
||||||
|
|
||||||
|
#if _COUNT != 0
|
||||||
|
template <class X, class R _COMMA _TMPLARG _COMMA _TMPLARGSPECS>
|
||||||
|
Methods
|
||||||
|
factory_callback (const std::string &name, R (X::*m) (_FUNCARGLIST) const, Callback X::*cb _COMMA _ARGSPECS, const std::string &doc = std::string ())
|
||||||
|
{
|
||||||
|
return Methods ((new _NAME(ConstMethod) <X, R _COMMA _FUNCARGLIST, gsi::return_new_object> (name, m, doc, cb))->add_args (_ARGSPECARGS));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// pointer iterators
|
// pointer iterators
|
||||||
|
|
||||||
template <class R _COMMA _TMPLARG>
|
template <class R _COMMA _TMPLARG>
|
||||||
|
|
|
||||||
|
|
@ -1158,5 +1158,86 @@ gsi::Class<SE> decl_se ("SE",
|
||||||
gsi::event ("s2", &SE::s2)
|
gsi::event ("s2", &SE::s2)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------
|
||||||
|
// G and GFactory implementation and GSI declarations
|
||||||
|
|
||||||
|
GObject::GObject ()
|
||||||
|
{
|
||||||
|
++s_g_inst_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
GObject::~GObject ()
|
||||||
|
{
|
||||||
|
--s_g_inst_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t GObject::s_g_inst_count = 0;
|
||||||
|
|
||||||
|
GObject_P::GObject_P ()
|
||||||
|
: GObject ()
|
||||||
|
{
|
||||||
|
// .. nothing yet ..
|
||||||
|
}
|
||||||
|
|
||||||
|
int GObject_P::g ()
|
||||||
|
{
|
||||||
|
return g_cb.can_issue () ? g_cb.issue<GObject, int> (&GObject::g) : GObject::g ();
|
||||||
|
}
|
||||||
|
|
||||||
|
GFactory::GFactory ()
|
||||||
|
{
|
||||||
|
// .. nothing yet ..
|
||||||
|
}
|
||||||
|
|
||||||
|
GFactory::~GFactory ()
|
||||||
|
{
|
||||||
|
// .. nothing yet ..
|
||||||
|
}
|
||||||
|
|
||||||
|
GFactory_P::GFactory_P ()
|
||||||
|
{
|
||||||
|
// .. nothing yet ..
|
||||||
|
}
|
||||||
|
|
||||||
|
GObject *GFactory_P::f (int z)
|
||||||
|
{
|
||||||
|
return f_cb.can_issue () ? f_cb.issue<GFactory, GObject *, int> (&GFactory::f, z) : GFactory::f (z);
|
||||||
|
}
|
||||||
|
|
||||||
|
int g_org (GObject_P *go)
|
||||||
|
{
|
||||||
|
return go->GObject::g ();
|
||||||
|
}
|
||||||
|
|
||||||
|
int g_virtual (GObject *go)
|
||||||
|
{
|
||||||
|
return go->g ();
|
||||||
|
}
|
||||||
|
|
||||||
|
static gsi::Class<GObject> decl_gobject_base ("GObjectBase",
|
||||||
|
gsi::method_ext ("g_virtual", &g_virtual) +
|
||||||
|
gsi::Methods()
|
||||||
|
);
|
||||||
|
|
||||||
|
static gsi::Class<GObject_P> decl_gobject (decl_gobject_base, "GObject",
|
||||||
|
gsi::method_ext ("g_org", &g_org) +
|
||||||
|
gsi::callback ("g", &GObject_P::g, &GObject_P::g_cb) +
|
||||||
|
gsi::method ("g_inst_count", &GObject::g_inst_count)
|
||||||
|
);
|
||||||
|
|
||||||
|
GObject *f_org (GFactory_P *fo, int z)
|
||||||
|
{
|
||||||
|
return fo->GFactory::f (z);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gsi::Class<GFactory> decl_gfactory_base ("GFactoryBase",
|
||||||
|
gsi::factory ("create_f", &GFactory::create_f)
|
||||||
|
);
|
||||||
|
|
||||||
|
static gsi::Class<GFactory_P> decl_gfactory (decl_gfactory_base, "GFactory",
|
||||||
|
gsi::method_ext ("f", &f_org) +
|
||||||
|
gsi::factory_callback ("f", &GFactory_P::f, &GFactory_P::f_cb)
|
||||||
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1044,6 +1044,54 @@ public:
|
||||||
gsi::Callback f_cb;
|
gsi::Callback f_cb;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// An object that is produced by a factory
|
||||||
|
class GObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GObject ();
|
||||||
|
virtual ~GObject ();
|
||||||
|
virtual int g () { return 0; }
|
||||||
|
static size_t g_inst_count ()
|
||||||
|
{
|
||||||
|
return s_g_inst_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static size_t s_g_inst_count;
|
||||||
|
};
|
||||||
|
|
||||||
|
class GObject_P : public GObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GObject_P ();
|
||||||
|
virtual int g ();
|
||||||
|
|
||||||
|
gsi::Callback g_cb;
|
||||||
|
};
|
||||||
|
|
||||||
|
// This is the factory for G
|
||||||
|
class GFactory
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GFactory ();
|
||||||
|
virtual ~GFactory ();
|
||||||
|
|
||||||
|
virtual GObject *f (int /*z*/) { return 0; }
|
||||||
|
static GObject *create_f (GFactory *g_factory, int z)
|
||||||
|
{
|
||||||
|
return g_factory->f (z);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class GFactory_P : public GFactory
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GFactory_P ();
|
||||||
|
virtual GObject *f (int z);
|
||||||
|
|
||||||
|
gsi::Callback f_cb;
|
||||||
|
};
|
||||||
|
|
||||||
class SQ
|
class SQ
|
||||||
: public QObject
|
: public QObject
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -509,7 +509,7 @@ Class<gsi::PluginFactoryBase> decl_PluginFactory ("PluginFactory",
|
||||||
"@args root\n"
|
"@args root\n"
|
||||||
"@param root The reference to the \\MainWindow object\n"
|
"@param root The reference to the \\MainWindow object\n"
|
||||||
) +
|
) +
|
||||||
callback ("create_plugin", &gsi::PluginFactoryBase::create_plugin_gsi, &gsi::PluginFactoryBase::f_create_plugin,
|
factory_callback ("create_plugin", &gsi::PluginFactoryBase::create_plugin_gsi, &gsi::PluginFactoryBase::f_create_plugin,
|
||||||
"@brief Creates the plugin\n"
|
"@brief Creates the plugin\n"
|
||||||
"This is the basic functionality that the factory must provide. This method must create a plugin of the "
|
"This is the basic functionality that the factory must provide. This method must create a plugin of the "
|
||||||
"specific type.\n"
|
"specific type.\n"
|
||||||
|
|
|
||||||
|
|
@ -173,7 +173,7 @@ Callee::call (int id, gsi::SerialArgs &args, gsi::SerialArgs &ret) const
|
||||||
}
|
}
|
||||||
|
|
||||||
tl::Heap heap;
|
tl::Heap heap;
|
||||||
push_arg (meth->ret_type (), ret, result.get (), heap);
|
push_arg (meth->ret_type (), ret, meth->ret_type().pass_obj() ? result.release() : result.get (), heap);
|
||||||
|
|
||||||
|
|
||||||
// a Python callback must not leave temporary objects
|
// a Python callback must not leave temporary objects
|
||||||
|
|
|
||||||
|
|
@ -92,6 +92,22 @@ def ph(x):
|
||||||
else:
|
else:
|
||||||
return x.replace("X", "")
|
return x.replace("X", "")
|
||||||
|
|
||||||
|
class PyGObject(pya.GObject):
|
||||||
|
z = -1
|
||||||
|
def __init__(self, z):
|
||||||
|
super(PyGObject, self).__init__()
|
||||||
|
self.z = z
|
||||||
|
# reimplementation of "virtual int g()"
|
||||||
|
def g(self):
|
||||||
|
return self.z*2
|
||||||
|
|
||||||
|
class PyGFactory(pya.GFactory):
|
||||||
|
def __init__(self):
|
||||||
|
super(PyGFactory, self).__init__()
|
||||||
|
# reimplementation of "virtual GObject *f(int)"
|
||||||
|
def f(self, z):
|
||||||
|
return PyGObject(z)
|
||||||
|
|
||||||
class BasicTest(unittest.TestCase):
|
class BasicTest(unittest.TestCase):
|
||||||
|
|
||||||
def test_00(self):
|
def test_00(self):
|
||||||
|
|
@ -2693,6 +2709,17 @@ class BasicTest(unittest.TestCase):
|
||||||
self.assertEqual(sc.got_s0a, 0)
|
self.assertEqual(sc.got_s0a, 0)
|
||||||
self.assertEqual(sc.got_s0b, 0)
|
self.assertEqual(sc.got_s0b, 0)
|
||||||
|
|
||||||
|
# Custom factory implemented in Python
|
||||||
|
def test_80(self):
|
||||||
|
gc = pya.GObject.g_inst_count()
|
||||||
|
gf = PyGFactory()
|
||||||
|
go = pya.GFactory.create_f(gf, 17)
|
||||||
|
self.assertEqual(go.g_virtual(), 34)
|
||||||
|
self.assertEqual(go.g_org(), 0)
|
||||||
|
self.assertEqual(pya.GObject.g_inst_count(), gc + 1)
|
||||||
|
go = None
|
||||||
|
self.assertEqual(pya.GObject.g_inst_count(), gc)
|
||||||
|
|
||||||
# run unit tests
|
# run unit tests
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
suite = unittest.TestSuite()
|
suite = unittest.TestSuite()
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue