diff --git a/src/gsi/gsi/gsiClass.h b/src/gsi/gsi/gsiClass.h index c5d961523..b40407f28 100644 --- a/src/gsi/gsi/gsiClass.h +++ b/src/gsi/gsi/gsiClass.h @@ -1018,13 +1018,7 @@ const ClassBase *cls_decl () // piece of code at the same time and they interfere when storing the results. static const ClassBase *cd = 0; if (! cd) { - for (ClassBase::class_iterator c = ClassBase::begin_classes (); c != ClassBase::end_classes (); ++c) { - if (c->declaration () == &*c && c->is_of_type (typeid (X))) { - // assert: duplicate declaration objects for that class - tl_assert (cd == 0); - cd = &*c; - } - } + cd = class_by_typeinfo_no_assert (typeid (X)); if (!cd) { cd = fallback_cls_decl (typeid (X)); } diff --git a/src/gsi/gsi/gsiClassBase.cc b/src/gsi/gsi/gsiClassBase.cc index f9b5cffa6..5e40e4d15 100644 --- a/src/gsi/gsi/gsiClassBase.cc +++ b/src/gsi/gsi/gsiClassBase.cc @@ -489,46 +489,109 @@ ClassBase::add_method (MethodBase *method, bool /*base_class*/) m_methods.add_method (method); } +// TODO: thread-safe? Unlikely that multiple threads access this member - +// we do a initial scan and after this no more write access here. +static std::map s_name_to_class; + +const ClassBase *class_by_name_no_assert (const std::string &name) +{ + if (s_name_to_class.empty ()) { + + for (gsi::ClassBase::class_iterator c = gsi::ClassBase::begin_classes (); c != gsi::ClassBase::end_classes (); ++c) { + + if (c->declaration () != c.operator-> ()) { + continue; + } + + if (!s_name_to_class.insert (std::make_pair (c->name (), c.operator-> ())).second) { + // Duplicate registration of this class + tl::error << "Duplicate registration of class " << c->name (); + tl_assert (false); + } + + } + + } + + std::map::const_iterator c = s_name_to_class.find (name); + if (c != s_name_to_class.end ()) { + return c->second; + } else { + return 0; + } +} + const ClassBase *class_by_name (const std::string &name) { - for (gsi::ClassBase::class_iterator c = gsi::ClassBase::begin_classes (); c != gsi::ClassBase::end_classes (); ++c) { - if (c->declaration () == &*c && c->name () == name) { - return &*c; - } - } - // No class with that name - tl_assert (false); + const ClassBase *cd = class_by_name_no_assert (name); + tl_assert (cd != 0); + return cd; } bool has_class (const std::string &name) { - for (gsi::ClassBase::class_iterator c = gsi::ClassBase::begin_classes (); c != gsi::ClassBase::end_classes (); ++c) { - if (c->declaration () == &*c && c->name () == name) { - return true; - } + return class_by_name (name) != 0; +} + +namespace +{ + +struct type_info_compare +{ + bool operator() (const std::type_info *a, const std::type_info *b) const + { + return a->before (*b); + } +}; + +} + +// TODO: thread-safe? Unlikely that multiple threads access this member - +// we do a initial scan and after this no more write access here. +static std::map s_ti_to_class; + +const ClassBase *class_by_typeinfo_no_assert (const std::type_info &ti) +{ + if (s_ti_to_class.empty ()) { + + for (gsi::ClassBase::class_iterator c = gsi::ClassBase::begin_classes (); c != gsi::ClassBase::end_classes (); ++c) { + + if (c->declaration () != c.operator-> ()) { + continue; + } + + const std::type_info *ti = c->adapted_type_info (); + if (! ti) { + ti = &c->type (); + } + if (ti && c->is_of_type (*ti) && !s_ti_to_class.insert (std::make_pair (ti, c.operator-> ())).second) { + // Duplicate registration of this class + tl::error << "Duplicate registration of class " << c->name () << " (type " << ti->name () << ")"; + tl_assert (false); + } + + } + + } + + std::map::const_iterator c = s_ti_to_class.find (&ti); + if (c != s_ti_to_class.end ()) { + return c->second; + } else { + return 0; } - return false; } const ClassBase *class_by_typeinfo (const std::type_info &ti) { - for (gsi::ClassBase::class_iterator c = gsi::ClassBase::begin_classes (); c != gsi::ClassBase::end_classes (); ++c) { - if (c->declaration () == &*c && c->is_of_type (ti)) { - return &*c; - } - } - // No class with that type - tl_assert (false); + const ClassBase *cd = class_by_typeinfo_no_assert (ti); + tl_assert (cd != 0); + return cd; } bool has_class (const std::type_info &ti) { - for (gsi::ClassBase::class_iterator c = gsi::ClassBase::begin_classes (); c != gsi::ClassBase::end_classes (); ++c) { - if (c->declaration () == &*c && c->is_of_type (ti)) { - return true; - } - } - return false; + return class_by_typeinfo_no_assert (ti) != 0; } } diff --git a/src/gsi/gsi/gsiClassBase.h b/src/gsi/gsi/gsiClassBase.h index d8fa37758..a228bb977 100644 --- a/src/gsi/gsi/gsiClassBase.h +++ b/src/gsi/gsi/gsiClassBase.h @@ -584,6 +584,14 @@ private: */ GSI_PUBLIC const ClassBase *class_by_name (const std::string &name); +/** + * @brief Accessor to a declaration through name + * + * This version won't assert when there is no such class and + * return 0 instead. + */ +GSI_PUBLIC const ClassBase *class_by_name_no_assert (const std::string &name); + /** * @brief Returns true if there is a class with the given name */ @@ -594,6 +602,14 @@ GSI_PUBLIC bool has_class (const std::string &name); */ GSI_PUBLIC const ClassBase *class_by_typeinfo (const std::type_info &ti); +/** + * @brief Find a class declaration through the type info + * + * This version won't assert when there is no such class and + * return 0 instead. + */ +GSI_PUBLIC const ClassBase *class_by_typeinfo_no_assert (const std::type_info &ti); + /** * @brief Returns true if there is a class with the given type info */