mirror of https://github.com/KLayout/klayout.git
Some performance enhancement (~30%) of RBA/PYA
This was achieved by separating the methods into constructors and callbacks, hence there are less iterations required when lookup up the latter.
This commit is contained in:
parent
a5d9bbb3d1
commit
c891d06ac3
|
|
@ -98,10 +98,10 @@ struct vector_defs
|
|||
{
|
||||
return
|
||||
constructor ("new", &new_v,
|
||||
"@brief Default constructor: creates a null vector with coordinates 0,0"
|
||||
"@brief Default constructor: creates a null vector with coordinates (0,0)"
|
||||
) +
|
||||
constructor ("new", &new_point,
|
||||
"@brief Default constructor: creates a vector to a point\n"
|
||||
"@brief Default constructor: creates a vector from a point\n"
|
||||
"@args p\n"
|
||||
"This constructor is equivalent to computing p-point(0,0).\n"
|
||||
"This method has been introduced in version 0.25."
|
||||
|
|
|
|||
|
|
@ -106,11 +106,7 @@ ClassBase::is_derived_from (const ClassBase *base) const
|
|||
static bool
|
||||
is_constructor_of (const ClassBase *target, const MethodBase *m, const ClassBase *from)
|
||||
{
|
||||
if (! m->is_static ()) {
|
||||
// only static methods are constructors
|
||||
return false;
|
||||
}
|
||||
if (! m->ret_type ().pass_obj () || ! m->ret_type ().is_ptr () || m->ret_type ().cls () != target) {
|
||||
if (m->ret_type ().cls () != target) {
|
||||
// the return type has to be a new'd pointer of the right type
|
||||
return false;
|
||||
}
|
||||
|
|
@ -139,7 +135,7 @@ is_constructor_of (const ClassBase *target, const MethodBase *m, const ClassBase
|
|||
bool
|
||||
ClassBase::can_convert_to (const ClassBase *target) const
|
||||
{
|
||||
for (method_iterator m = target->begin_methods (); m != target->end_methods (); ++m) {
|
||||
for (method_iterator m = target->begin_constructors (); m != target->end_constructors (); ++m) {
|
||||
if (is_constructor_of (target, *m, this)) {
|
||||
return true;
|
||||
}
|
||||
|
|
@ -152,7 +148,7 @@ ClassBase::create_obj_from (const ClassBase *from, void *obj) const
|
|||
{
|
||||
const MethodBase *ctor = 0;
|
||||
|
||||
for (method_iterator m = begin_methods (); m != end_methods (); ++m) {
|
||||
for (method_iterator m = begin_constructors (); m != end_constructors (); ++m) {
|
||||
if (is_constructor_of (this, *m, from)) {
|
||||
if (ctor) {
|
||||
throw tl::Exception (tl::to_string (QObject::tr ("There are multiple conversion constructors available to convert object of type %s to type %s")), from->name (), name ());
|
||||
|
|
@ -467,6 +463,26 @@ ClassBase::merge_declarations ()
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
ClassBase::initialize ()
|
||||
{
|
||||
m_methods.initialize ();
|
||||
|
||||
m_constructors.clear ();
|
||||
for (Methods::iterator m = m_methods.begin (); m != m_methods.end (); ++m) {
|
||||
if ((*m)->is_constructor ()) {
|
||||
m_constructors.push_back (*m);
|
||||
}
|
||||
}
|
||||
|
||||
m_callbacks.clear ();
|
||||
for (Methods::iterator m = m_methods.begin (); m != m_methods.end (); ++m) {
|
||||
if ((*m)->is_callback ()) {
|
||||
m_callbacks.push_back (*m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ClassBase::add_method (MethodBase *method, bool /*base_class*/)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -144,14 +144,6 @@ public:
|
|||
return m_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the method declaration collection
|
||||
*/
|
||||
Methods &methods ()
|
||||
{
|
||||
return m_methods;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the documentation string
|
||||
*/
|
||||
|
|
@ -235,6 +227,38 @@ public:
|
|||
return m_methods.end ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Iterates the constructor methods (begin)
|
||||
*/
|
||||
method_iterator begin_constructors () const
|
||||
{
|
||||
return m_constructors.begin ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Iterates the constructor methods (end)
|
||||
*/
|
||||
method_iterator end_constructors () const
|
||||
{
|
||||
return m_constructors.end ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Iterates the callback methods (begin)
|
||||
*/
|
||||
method_iterator begin_callbacks () const
|
||||
{
|
||||
return m_callbacks.begin ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Iterates the callback methods (end)
|
||||
*/
|
||||
method_iterator end_callbacks () const
|
||||
{
|
||||
return m_callbacks.end ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns true, if this class is derived from the given base class
|
||||
*/
|
||||
|
|
@ -476,10 +500,7 @@ public:
|
|||
* In that case, this initialization step is useful. It will call the initialize
|
||||
* method on all method declarations.
|
||||
*/
|
||||
virtual void initialize ()
|
||||
{
|
||||
m_methods.initialize ();
|
||||
}
|
||||
virtual void initialize ();
|
||||
|
||||
/**
|
||||
* @brief Adds a method to the class
|
||||
|
|
@ -545,12 +566,17 @@ private:
|
|||
const ClassBase *mp_base, *mp_parent;
|
||||
std::string m_doc;
|
||||
Methods m_methods;
|
||||
std::vector<MethodBase *> m_callbacks, m_constructors;
|
||||
std::string m_name;
|
||||
tl::weak_collection<ClassBase> m_child_classes, m_subclasses;
|
||||
mutable std::auto_ptr<PerClassClientSpecificData> mp_data[ClientIndex::MaxClientIndex];
|
||||
|
||||
static class_collection *mp_class_collection;
|
||||
static unsigned int m_class_count;
|
||||
|
||||
// No copying
|
||||
ClassBase (const ClassBase &other);
|
||||
ClassBase &operator= (const ClassBase &other);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -250,6 +250,11 @@ Class<MethodBase> decl_Method ("Method",
|
|||
gsi::method ("is_static?", &MethodBase::is_static,
|
||||
"@brief True, if this method is static (a class method)\n"
|
||||
) +
|
||||
gsi::method ("is_constructor?", &MethodBase::is_constructor,
|
||||
"@brief True, if this method is a constructor\n"
|
||||
"Static methods that return new objects are constructors.\n"
|
||||
"This method has been introduced in version 0.25."
|
||||
) +
|
||||
gsi::method ("is_signal?", &MethodBase::is_signal,
|
||||
"@brief True, if this method is a signal\n"
|
||||
"\n"
|
||||
|
|
|
|||
|
|
@ -275,6 +275,16 @@ public:
|
|||
return m_static;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicator whether the method is a constructor
|
||||
*
|
||||
* Static methods returning a new object are constructors.
|
||||
*/
|
||||
bool is_constructor () const
|
||||
{
|
||||
return (is_static () && ret_type ().pass_obj () && ret_type ().is_ptr ());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a value indicating whether the method is compatible with the given number of arguments
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -523,9 +523,9 @@ PYAObjectBase::initialize_callbacks ()
|
|||
// (the object has been created on C++ side).
|
||||
while (cls) {
|
||||
|
||||
for (gsi::ClassBase::method_iterator m = cls->begin_methods (); m != cls->end_methods (); ++m) {
|
||||
for (gsi::ClassBase::method_iterator m = cls->begin_callbacks (); m != cls->end_callbacks (); ++m) {
|
||||
|
||||
if ((*m)->is_callback () && m_owned) {
|
||||
if (m_owned) {
|
||||
|
||||
// NOTE: only Python-implemented classes can reimplement methods. Since we
|
||||
// take the attribute from the class object, only Python instances can overwrite
|
||||
|
|
|
|||
|
|
@ -479,37 +479,33 @@ Proxy::initialize_callbacks ()
|
|||
// (the object has been created on C++ side).
|
||||
while (cls) {
|
||||
|
||||
for (gsi::ClassBase::method_iterator m = cls->begin_methods (); m != cls->end_methods (); ++m) {
|
||||
for (gsi::ClassBase::method_iterator m = cls->begin_callbacks (); m != cls->end_callbacks (); ++m) {
|
||||
|
||||
if ((*m)->is_callback ()) {
|
||||
// HINT: all callback may not have aliases nor overloads
|
||||
const char *nstr = (*m)->primary_name ().c_str ();
|
||||
|
||||
// HINT: all callback may not have aliases nor overloads
|
||||
const char *nstr = (*m)->primary_name ().c_str ();
|
||||
// There is no place in the ruby API to determine whether a method is defined.
|
||||
// Instead we explicitly call "method_defined?" to check, whether the given method
|
||||
// is defined.
|
||||
VALUE name = rb_str_new (nstr, strlen (nstr));
|
||||
RB_GC_GUARD (name);
|
||||
|
||||
// There is no place in the ruby API to determine whether a method is defined.
|
||||
// Instead we explicitly call "method_defined?" to check, whether the given method
|
||||
// is defined.
|
||||
VALUE name = rb_str_new (nstr, strlen (nstr));
|
||||
RB_GC_GUARD (name);
|
||||
for (int prot = 0; prot < 2; ++prot) {
|
||||
|
||||
for (int prot = 0; prot < 2; ++prot) {
|
||||
VALUE rb_ret;
|
||||
if (prot) {
|
||||
rb_ret = rba_funcall2_checked (rb_class_of (m_self), rb_intern ("protected_method_defined?"), 1, &name);
|
||||
} else {
|
||||
rb_ret = rba_funcall2_checked (rb_class_of (m_self), rb_intern ("method_defined?"), 1, &name);
|
||||
}
|
||||
if (RTEST (rb_ret)) {
|
||||
|
||||
VALUE rb_ret;
|
||||
if (prot) {
|
||||
rb_ret = rba_funcall2_checked (rb_class_of (m_self), rb_intern ("protected_method_defined?"), 1, &name);
|
||||
} else {
|
||||
rb_ret = rba_funcall2_checked (rb_class_of (m_self), rb_intern ("method_defined?"), 1, &name);
|
||||
}
|
||||
if (RTEST (rb_ret)) {
|
||||
// Only if the class defines that method we can link the virtual method call to the
|
||||
// Ruby method
|
||||
int id = add_callback (Proxy::CallbackFunction (rb_intern (nstr), *m));
|
||||
(*m)->set_callback (m_obj, gsi::Callback (id, this, (*m)->argsize (), (*m)->retsize ()));
|
||||
|
||||
// Only if the class defines that method we can link the virtual method call to the
|
||||
// Ruby method
|
||||
int id = add_callback (Proxy::CallbackFunction (rb_intern (nstr), *m));
|
||||
(*m)->set_callback (m_obj, gsi::Callback (id, this, (*m)->argsize (), (*m)->retsize ()));
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -538,10 +534,8 @@ Proxy::clear_callbacks ()
|
|||
while (cls) {
|
||||
|
||||
// reset all callbacks
|
||||
for (gsi::ClassBase::method_iterator m = cls->begin_methods (); m != cls->end_methods (); ++m) {
|
||||
if ((*m)->is_callback ()) {
|
||||
(*m)->set_callback (m_obj, gsi::Callback ());
|
||||
}
|
||||
for (gsi::ClassBase::method_iterator m = cls->begin_callbacks (); m != cls->end_callbacks (); ++m) {
|
||||
(*m)->set_callback (m_obj, gsi::Callback ());
|
||||
}
|
||||
|
||||
// consider base classes as well.
|
||||
|
|
|
|||
|
|
@ -1078,7 +1078,7 @@ class DBLayout_TestClass < TestBase
|
|||
# Slow cleanup test
|
||||
def test_13
|
||||
|
||||
n = 1000
|
||||
n = 100
|
||||
w = 10000
|
||||
|
||||
ly = RBA::Layout::new
|
||||
|
|
|
|||
Loading…
Reference in New Issue