diff --git a/src/db/gsiDeclDbVector.cc b/src/db/gsiDeclDbVector.cc index d2c2b5c51..c7838a1c2 100644 --- a/src/db/gsiDeclDbVector.cc +++ b/src/db/gsiDeclDbVector.cc @@ -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." diff --git a/src/gsi/gsiClassBase.cc b/src/gsi/gsiClassBase.cc index 7af8108e6..685ea377f 100644 --- a/src/gsi/gsiClassBase.cc +++ b/src/gsi/gsiClassBase.cc @@ -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*/) { diff --git a/src/gsi/gsiClassBase.h b/src/gsi/gsiClassBase.h index 94a08d628..d8fa37758 100644 --- a/src/gsi/gsiClassBase.h +++ b/src/gsi/gsiClassBase.h @@ -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 m_callbacks, m_constructors; std::string m_name; tl::weak_collection m_child_classes, m_subclasses; mutable std::auto_ptr 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); }; /** diff --git a/src/gsi/gsiDeclInternal.cc b/src/gsi/gsiDeclInternal.cc index 78cc5b384..311c8dc64 100644 --- a/src/gsi/gsiDeclInternal.cc +++ b/src/gsi/gsiDeclInternal.cc @@ -250,6 +250,11 @@ Class 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" diff --git a/src/gsi/gsiMethods.h b/src/gsi/gsiMethods.h index 3080886c9..3b994ba0b 100644 --- a/src/gsi/gsiMethods.h +++ b/src/gsi/gsiMethods.h @@ -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 */ diff --git a/src/pya/pyaObject.cc b/src/pya/pyaObject.cc index af3aee816..7a8168350 100644 --- a/src/pya/pyaObject.cc +++ b/src/pya/pyaObject.cc @@ -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 diff --git a/src/rba/rbaInternal.cc b/src/rba/rbaInternal.cc index 09ef6a978..7e0ee648f 100644 --- a/src/rba/rbaInternal.cc +++ b/src/rba/rbaInternal.cc @@ -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. diff --git a/testdata/ruby/dbLayoutTest.rb b/testdata/ruby/dbLayoutTest.rb index 79a8e82f6..7bb6ee2d3 100644 --- a/testdata/ruby/dbLayoutTest.rb +++ b/testdata/ruby/dbLayoutTest.rb @@ -1078,7 +1078,7 @@ class DBLayout_TestClass < TestBase # Slow cleanup test def test_13 - n = 1000 + n = 100 w = 10000 ly = RBA::Layout::new