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:
Matthias Koefferlein 2017-06-12 00:31:00 +02:00
parent a5d9bbb3d1
commit c891d06ac3
8 changed files with 104 additions and 53 deletions

View File

@ -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."

View File

@ -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*/)
{

View File

@ -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);
};
/**

View File

@ -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"

View File

@ -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
*/

View File

@ -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

View File

@ -479,9 +479,7 @@ 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) {
if ((*m)->is_callback ()) {
for (gsi::ClassBase::method_iterator m = cls->begin_callbacks (); m != cls->end_callbacks (); ++m) {
// HINT: all callback may not have aliases nor overloads
const char *nstr = (*m)->primary_name ().c_str ();
@ -515,8 +513,6 @@ Proxy::initialize_callbacks ()
}
}
// consider base classes as well.
cls = cls->base ();
@ -538,11 +534,9 @@ 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 ()) {
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.
cls = cls->base ();

View File

@ -1078,7 +1078,7 @@ class DBLayout_TestClass < TestBase
# Slow cleanup test
def test_13
n = 1000
n = 100
w = 10000
ly = RBA::Layout::new