klayout/src/gsi/gsiClass.h

1038 lines
26 KiB
C++

/*
KLayout Layout Viewer
Copyright (C) 2006-2017 Matthias Koefferlein
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _HDR_gsiClass
#define _HDR_gsiClass
#include "gsiObject.h"
#include "tlTypeTraits.h"
#include "tlHeap.h"
#include "tlUtils.h"
#include <memory>
// For a comprehensive documentation see gsi.h
namespace gsi
{
// -----------------------------------------------------------------------------
// Variant binding
/**
* @brief A helper function to implement equal as efficiently as possible
*/
template<class T, class I>
bool _var_user_equal_impl (const T *a, const T *b, const VariantUserClassImpl *delegate, I);
template<class T>
bool _var_user_equal_impl (const T *a, const T *b, const VariantUserClassImpl * /*delegate*/, tl::true_tag)
{
return *a == *b;
}
template<class T>
bool _var_user_equal_impl (const T *a, const T *b, const VariantUserClassImpl *delegate, tl::false_tag)
{
return delegate->equal_impl ((void *) a, (void *) b);
}
/**
* @brief A helper function to implement less as efficiently as possible
*/
template<class T, class I>
bool _var_user_less_impl (const T *a, const T *b, const VariantUserClassImpl *delegate, I);
template<class T>
bool _var_user_less_impl (const T *a, const T *b, const VariantUserClassImpl * /*delegate*/, tl::true_tag)
{
return *a < *b;
}
template<class T>
bool _var_user_less_impl (const T *a, const T *b, const VariantUserClassImpl *delegate, tl::false_tag)
{
return delegate->less_impl ((void *) a, (void *) b);
}
/**
* @brief A helper function to implement to_string as efficiently as possible
*/
template<class T, class I>
std::string _var_user_to_string_impl (const T *a, const VariantUserClassImpl *delegate, I);
template<class T>
std::string _var_user_to_string_impl (const T *a, const VariantUserClassImpl * /*delegate*/, tl::true_tag)
{
return a->to_string ();
}
template<class T>
std::string _var_user_to_string_impl (const T *a, const VariantUserClassImpl *delegate, tl::false_tag)
{
return delegate->to_string_impl ((void *) a);
}
/**
* @brief A helper function to implement read as efficiently as possible
*/
template<class T, class I>
void _var_user_read_impl (T *a, tl::Extractor &ex, I);
template<class T>
void _var_user_read_impl (T *a, tl::Extractor &ex, tl::true_tag)
{
ex.read (*a);
}
template<class T>
void _var_user_read_impl (T * /*a*/, tl::Extractor & /*ex*/, tl::false_tag)
{
tl_assert (false);
}
/**
* @brief A VariantUserClassBase specialization that links GSI classes and Variant classes
*/
template <class T>
class VariantUserClass
: public tl::VariantUserClass<T>, private VariantUserClassImpl
{
public:
VariantUserClass ()
: VariantUserClassImpl (),
mp_cls (0), mp_object_cls (0), m_is_const (false)
{
// .. nothing yet ..
}
~VariantUserClass ()
{
mp_cls = 0;
tl::VariantUserClass<T>::unregister_instance (this, m_is_const);
}
void initialize (const gsi::ClassBase *cls, const tl::VariantUserClassBase *object_cls, bool is_const)
{
mp_cls = cls;
mp_object_cls = object_cls;
m_is_const = is_const;
VariantUserClassImpl::initialize (cls, this, object_cls, is_const);
if (! object_cls) {
// Register the const/non-const classes for the tl::Variant payload.
tl::VariantUserClass<T>::register_instance (this, m_is_const);
}
}
const tl::EvalClass *eval_cls () const
{
return this;
}
void *deref_proxy (tl::Object *proxy) const
{
Proxy *p = dynamic_cast<Proxy *> (proxy);
if (p) {
return p->obj ();
} else {
return 0;
}
}
virtual bool equal (const void *a, const void *b) const
{
typename tl::type_traits<T>::has_equal_operator f;
return gsi::_var_user_equal_impl ((const T *) a, (const T *) b, this, f);
}
virtual bool less (const void *a, const void *b) const
{
typename tl::type_traits<T>::has_less_operator f;
return gsi::_var_user_less_impl ((const T *) a, (const T *) b, this, f);
}
virtual std::string to_string (const void *a) const
{
typename tl::type_traits<T>::supports_to_string f;
return gsi::_var_user_to_string_impl ((const T *) a, this, f);
}
void *clone (const void *obj) const
{
void *new_obj = mp_cls->create ();
mp_cls->assign (new_obj, obj);
return new_obj;
}
void assign (void *self, const void *other) const
{
mp_cls->assign (self, other);
}
void *create () const
{
return mp_cls->create ();
}
void destroy (void *obj) const
{
if (obj) {
mp_cls->destroy (obj);
}
}
const char *name () const
{
return mp_cls ? mp_cls->name ().c_str() : 0;
}
void read (void *a, tl::Extractor &ex) const
{
typename tl::type_traits<T>::supports_extractor f;
gsi::_var_user_read_impl ((T *) a, ex, f);
}
const gsi::ClassBase *gsi_cls () const
{
return mp_cls;
}
bool is_class () const
{
return mp_object_cls != 0;
}
bool is_const () const
{
return m_is_const;
}
private:
const gsi::ClassBase *mp_cls;
const tl::VariantUserClassBase *mp_object_cls;
bool m_is_const;
// no copying currently
VariantUserClass &operator= (const VariantUserClass &);
VariantUserClass (const VariantUserClass &);
};
// -----------------------------------------------------------------------------
// GSI implementation
template <class X>
void *_get_vector_of (SerialArgs & /*from*/, const ArgType & /*a*/, void * /*data*/, void (* /*cb*/) (void * /*data*/, void * /*obj*/), tl::false_tag /*has_copy_ctor*/)
{
tl_assert (false); // cannot copy object of this type
return 0;
}
template <class X>
void _get_vector_of (SerialArgs &from, const ArgType &a, void *data, void (*cb) (void *data, void *obj), tl::true_tag /*has_copy_ctor*/)
{
std::vector<X> vv;
const std::vector<X> *v = &vv;
if (a.is_cref ()) {
v = &from.template read<const std::vector<X> &> ();
} else if (a.is_cptr ()) {
v = from.template read<const std::vector<X> *> ();
} else if (a.is_ref ()) {
v = &from.template read<std::vector<X> &> ();
} else if (a.is_ptr ()) {
v = from.template read<std::vector<X> *> ();
} else {
vv = from.template read< std::vector<X> > ();
}
for (typename std::vector<X>::const_iterator o = v->begin (); o != v->end (); ++o) {
(*cb) (data, new X (*o));
}
}
template <class X>
void _get_cptr_vector_of (SerialArgs &from, const ArgType &a, void *data, void (*cb) (void *data, void *obj))
{
std::vector<const X *> vv;
const std::vector<const X *> *v = &vv;
if (a.is_cref ()) {
v = &from.template read<const std::vector<const X *> &> ();
} else if (a.is_cptr ()) {
v = from.template read<const std::vector<const X *> *> ();
} else if (a.is_ref ()) {
v = &from.template read<std::vector<const X *> &> ();
} else if (a.is_ptr ()) {
v = from.template read<std::vector<const X *> *> ();
} else {
vv = from.template read< std::vector<const X *> > ();
}
for (typename std::vector<const X *>::const_iterator o = v->begin (); o != v->end (); ++o) {
(*cb) (data, (void *) *o);
}
}
template <class X>
void _get_ptr_vector_of (SerialArgs &from, const ArgType &a, void *data, void (*cb) (void *data, void *obj))
{
std::vector<X *> vv;
const std::vector<X *> *v = &vv;
if (a.is_cref ()) {
v = &from.template read<const std::vector<X *> &> ();
} else if (a.is_cptr ()) {
v = from.template read<const std::vector<X *> *> ();
} else if (a.is_ref ()) {
v = &from.template read<std::vector<X *> &> ();
} else if (a.is_ptr ()) {
v = from.template read<std::vector<X *> *> ();
} else {
vv = from.template read< std::vector<X *> > ();
}
for (typename std::vector<X *>::const_iterator o = v->begin (); o != v->end (); ++o) {
(*cb) (data, *o);
}
}
template <class X>
void _destroy (X *, tl::false_tag /*has public dtor*/)
{
tl_assert (false); // cannot delete object of this type
}
template <class X>
void _destroy (X *x, tl::true_tag /*has public dtor*/)
{
delete x;
}
template <class X>
void _push_vector_of (SerialArgs & /*to*/, const ArgType & /*a*/, tl::Heap & /*heap*/, const std::vector<void *> & /*objects*/, tl::false_tag /*has_copy_ctor*/)
{
tl_assert (false); // cannot copy object of this type
}
template <class X>
void _push_vector_of (SerialArgs &to, const ArgType &a, tl::Heap &heap, const std::vector<void *> &objects, tl::true_tag /*has_copy_ctor*/)
{
tl_assert (a.inner () != 0);
std::vector<X> vv;
std::vector<X> *v;
if (a.is_ref () || a.is_cref () || a.is_ptr () || a.is_cptr ()) {
v = new std::vector<X> ();
heap.push (v);
} else {
v = &vv;
}
v->reserve (objects.size ());
for (std::vector<void *>::const_iterator o = objects.begin (); o != objects.end (); ++o) {
v->push_back (*(X *)*o);
}
if (a.is_cref ()) {
to.write<const std::vector<X> &> (*v);
} else if (a.is_cptr ()) {
to.write<const std::vector<X> *> (v);
} else if (a.is_ref ()) {
to.write<std::vector<X> &> (*v);
} else if (a.is_ptr ()) {
to.write<std::vector<X> *> (v);
} else {
to.write<std::vector<X> > (vv);
}
}
template <class X>
void _push_cptr_vector_of (SerialArgs &to, const ArgType &a, tl::Heap &heap, const std::vector<void *> &objects)
{
tl_assert (a.inner () != 0);
std::vector<const X *> vv;
std::vector<const X *> *v;
if (a.is_ref () || a.is_cref () || a.is_ptr () || a.is_cptr ()) {
v = new std::vector<const X *> ();
heap.push (v);
} else {
v = &vv;
}
v->reserve (objects.size ());
for (std::vector<void *>::const_iterator o = objects.begin (); o != objects.end (); ++o) {
v->push_back ((const X *)*o);
}
if (a.is_cref ()) {
to.write<const std::vector<const X *> &> (*v);
} else if (a.is_cptr ()) {
to.write<const std::vector<const X *> *> (v);
} else if (a.is_ref ()) {
to.write<std::vector<const X *> &> (*v);
} else if (a.is_ptr ()) {
to.write<std::vector<const X *> *> (v);
} else {
to.write<std::vector<const X *> > (vv);
}
}
template <class X>
void _push_ptr_vector_of (SerialArgs &to, const ArgType &a, tl::Heap &heap, const std::vector<void *> &objects)
{
tl_assert (a.inner () != 0);
std::vector<X *> vv;
std::vector<X *> *v;
if (a.is_ref () || a.is_cref () || a.is_ptr () || a.is_cptr ()) {
v = new std::vector<X *> ();
heap.push (v);
} else {
v = &vv;
}
v->reserve (objects.size ());
for (std::vector<void *>::const_iterator o = objects.begin (); o != objects.end (); ++o) {
v->push_back ((X *)*o);
}
if (a.is_cref ()) {
to.write<const std::vector<X *> &> (*v);
} else if (a.is_cptr ()) {
to.write<const std::vector<X *> *> (v);
} else if (a.is_ref ()) {
to.write<std::vector<X *> &> (*v);
} else if (a.is_ptr ()) {
to.write<std::vector<X *> *> (v);
} else {
to.write<std::vector<X *> > (vv);
}
}
template <class X>
void *_create (tl::false_tag)
{
throw tl::Exception (tl::to_string (QObject::tr ("Object cannot be created here")));
return 0;
}
template <class X>
void *_create (tl::true_tag)
{
return new X ();
}
template <class X>
void *_clone (tl::false_tag, const void * /*other*/)
{
throw tl::Exception (tl::to_string (QObject::tr ("Object cannot be copied here")));
return 0;
}
template <class X>
void *_clone (tl::true_tag, const void *other)
{
return new X (*(const X *)other);
}
template <class X>
void _assign (tl::false_tag /*has_copy_ctor*/, void *, const void *)
{
throw tl::Exception (tl::to_string (QObject::tr ("Object cannot be copied here")));
}
template <class X>
void _assign (tl::true_tag /*has_copy_ctor*/, void *dest, const void *src)
{
*(X *)dest = *(const X *)src;
}
/**
* @brief A class predicate telling us whether X is polymorphic
*
* The trick was taken from boost - if a class is made polymorphic and it
* has not been before, the size of the object changes since a virtual
* function table will be added.
*/
template <class X>
struct is_polymorphic
{
private:
struct P1 : public X
{
P1 ();
~P1 ();
int something;
};
struct P2 : public X
{
P2 ();
virtual ~P2 ();
int something;
};
public:
typedef typename tl::boolean_value<sizeof (P1) == sizeof (P2)>::value value;
};
/**
* @brief A helper class which tests whether a given object can be upcast
*/
class SubClassTesterBase
{
public:
SubClassTesterBase () { }
virtual ~SubClassTesterBase () { }
virtual bool can_upcast (const void *p) const = 0;
};
/**
* @brief A specific implementation of the upcast tester
*
* The can_upcast method will return true, if the object (which has at least to
* be of type B) can be upcast to X.
*/
template <class X, class B, class B_IS_POLYMORPHIC>
class SubClassTester;
/**
* @brief Specialization for polymorphic types - we can use dynamic_cast to tests whether B object can be cast to X
*/
template <class X, class B>
class SubClassTester<X, B, tl::true_tag>
: public SubClassTesterBase
{
public:
virtual bool can_upcast (const void *p) const
{
return dynamic_cast<const X *>((const B *)p) != 0;
}
};
/**
* @brief Specialization for non-polymorphic types
*/
template <class X, class B>
class SubClassTester<X, B, tl::false_tag>
: public SubClassTesterBase
{
public:
virtual bool can_upcast (const void *) const
{
// Non-polymorphic classes can't be upcast, hence we always return false here
return false;
}
};
/**
* @brief An extension declaration
*
* Instantiating an object of this kind will extend the class X with
* the given methods.
*/
template <class X>
class ClassExt
: public ClassBase
{
public:
typedef typename tl::type_traits<X>::has_copy_constructor has_copy_ctor;
typedef typename tl::type_traits<X>::has_default_constructor has_default_ctor;
typedef typename tl::type_traits<X>::has_public_destructor has_public_dtor;
ClassExt (const Methods &mm, const std::string &doc = std::string ())
: ClassBase (doc, mm), mp_declaration (0)
{
// .. nothing yet ..
}
ClassExt (const std::string &doc = std::string ())
: ClassBase (doc, Methods ()), mp_declaration (0)
{
// .. nothing yet ..
}
/**
* @brief Imports a class into this class
* This constructor will pull in another class into this one as a kind of link using
* a different name.
* This feature is not quite useful usually and is reserved for special use cases
* such as including enums into a declaration namespace.
*/
ClassExt (const ClassBase &import, const std::string &name, const std::string &doc = std::string ())
: ClassBase (doc, Methods ()), mp_declaration (&import)
{
set_name (name);
}
virtual bool is_of_type (const std::type_info &ti) const
{
return (ti == typeid (X));
}
virtual const std::type_info &type () const
{
return typeid (X);
}
/**
* @brief Gets the real (main) declaration object
* The main declaration object is 0 initially indicating that the classes
* have not been merged.
*/
virtual const ClassBase *declaration () const
{
return mp_declaration;
}
virtual bool consolidate () const
{
// gets the "real" declaration by the type info
// TODO: ugly const_cast hack
ClassBase *non_const_decl = const_cast<ClassBase *> (cls_decl<X> ());
// transfer the methods
for (gsi::ClassBase::method_iterator m = begin_methods (); m != end_methods (); ++m) {
non_const_decl->add_method ((*m)->clone ());
}
// Treat class imports (extensions with a base class): import the class as
// a child class plus import constants into the class (intended for enum import).
if (declaration ()) {
non_const_decl->add_child_class (this);
}
// No longer required
return false;
}
private:
const ClassBase *mp_declaration;
};
/**
* @brief A tag indicating "no adaptor"
*/
struct NoAdaptorTag { };
/**
* @brief Delivers the typeid for the given class
*/
template <class X, class Adapted>
struct adaptor_type_info
{
static const std::type_info *type_info ()
{
return &typeid (Adapted);
}
static X *create (const Adapted *a)
{
return new X (*a);
}
static X *create_consume (Adapted *a)
{
X *x = new X (*a);
delete a;
return x;
}
static const Adapted *get (const X *x)
{
return &x->value ();
}
static Adapted *create_adapted (const X *x)
{
return new Adapted (x->value ());
}
};
template <class X>
struct adaptor_type_info<X, NoAdaptorTag>
{
static const std::type_info *type_info ()
{
return 0;
}
static X *create (const NoAdaptorTag *)
{
tl_assert (false);
return 0;
}
static X *create_consume (NoAdaptorTag *)
{
tl_assert (false);
return 0;
}
static const NoAdaptorTag *get (const X *)
{
tl_assert (false);
return 0;
}
static NoAdaptorTag *create_adapted (const X *)
{
tl_assert (false);
return 0;
}
};
/**
* @brief The declaration of a specific class
*
* This class declares all methods that are required to instantiate or copy an object
* or to call it's methods in some generic way.
*/
template <class X, class Adapted = NoAdaptorTag>
class Class
: public ClassBase
{
public:
typedef typename tl::type_traits<X>::has_copy_constructor has_copy_ctor;
typedef typename tl::type_traits<X>::has_default_constructor has_default_ctor;
typedef typename tl::type_traits<X>::has_public_destructor has_public_dtor;
Class (const std::string &name, const Methods &mm, const std::string &doc = std::string (), bool do_register = true)
: ClassBase (doc, mm, do_register)
{
set_name (name);
}
template <class B>
Class (const Class<B> &base, const std::string &name, const Methods &mm, const std::string &doc = std::string (), bool do_register = true)
: ClassBase (doc, mm, do_register), m_subclass_tester (new SubClassTester<X, B, typename is_polymorphic<B>::value> ())
{
set_name (name);
set_base (&base);
}
Class (const std::string &name, const std::string &doc = std::string (), bool do_register = true)
: ClassBase (doc, Methods (), do_register)
{
set_name (name);
}
template <class B>
Class (const Class<B> &base, const std::string &name, const std::string &doc = std::string (), bool do_register = true)
: ClassBase (doc, Methods (), do_register), m_subclass_tester (new SubClassTester<X, B, typename is_polymorphic<B>::value> ())
{
set_name (name);
set_base (&base);
}
virtual const std::type_info *adapted_type_info () const
{
return adaptor_type_info<X, Adapted>::type_info ();
}
virtual const ClassBase *declaration () const
{
return this;
}
virtual bool consolidate () const
{
return true;
}
void initialize ()
{
ClassBase::initialize ();
m_var_cls.initialize (this, 0, false);
m_var_cls_c.initialize (this, 0, true);
m_var_cls_cls.initialize (this, &m_var_cls, false);
}
bool is_managed () const
{
return tl::is_derived<gsi::ObjectBase, X> ();
}
gsi::ObjectBase *gsi_object (void *p, bool /*required*/) const
{
return tl::try_static_cast<gsi::ObjectBase, X> ((X *) p);
}
virtual void destroy (void *p) const
{
X *x = (X *)p;
has_public_dtor hpd;
_destroy (x, hpd);
}
virtual void *create () const
{
has_default_ctor cst;
void *r = _create<X> (cst);
return r;
}
virtual void *create_from_adapted (const void *x) const
{
return adaptor_type_info<X, Adapted>::create ((const Adapted *) x);
}
virtual void *create_from_adapted_consume (void *x) const
{
return adaptor_type_info<X, Adapted>::create_consume ((Adapted *) x);
}
virtual const void *adapted_from_obj (const void *obj) const
{
return adaptor_type_info<X, Adapted>::get ((const X *) obj);
}
virtual void *create_adapted_from_obj (const void *obj) const
{
return adaptor_type_info<X, Adapted>::create_adapted ((const X *) obj);
}
virtual void *clone (const void *other) const
{
has_copy_ctor cst;
void *r = _clone<X> (cst, other);
return r;
}
virtual void assign (void *dest, const void *src) const
{
has_copy_ctor cst;
_assign<X> (cst, dest, src);
}
virtual bool can_destroy () const
{
has_public_dtor hpd;
return tl::value_of (hpd);
}
virtual bool can_copy () const
{
has_copy_ctor cpt;
return tl::value_of (cpt);
}
virtual bool can_default_create () const
{
has_default_ctor cpt;
return tl::value_of (cpt);
}
virtual const ClassBase *subclass_decl (const void *p) const
{
if (p) {
for (tl::weak_collection<ClassBase>::const_iterator s = subclasses ().begin (); s != subclasses ().end (); ++s) {
if (s->can_upcast (p)) {
return s->subclass_decl (p);
}
}
}
return this;
}
virtual bool can_upcast (const void *p) const
{
return m_subclass_tester.get () && m_subclass_tester->can_upcast (p);
}
virtual bool is_of_type (const std::type_info &ti) const
{
if (adapted_type_info ()) {
// A class matches the typeinfo of the adapted type. We'll sort this out later
// on the client side.
return (ti == *adapted_type_info ());
} else {
return (ti == typeid (X));
}
}
virtual const std::type_info &type () const
{
return typeid (X);
}
virtual const tl::VariantUserClassBase *var_cls_cls () const
{
return &m_var_cls_cls;
}
virtual const tl::VariantUserClassBase *var_cls (bool is_const) const
{
if (is_const) {
return &m_var_cls_c;
} else {
return &m_var_cls;
}
}
private:
gsi::VariantUserClass<X> m_var_cls;
gsi::VariantUserClass<X> m_var_cls_c;
gsi::VariantUserClass<X> m_var_cls_cls;
std::auto_ptr<SubClassTesterBase> m_subclass_tester;
};
/**
* @brief The declaration of a class with a base class
*
* This is an alternative to using the Class constructor with a base class reference. It
* employs a template parameter rather than a gsi::Class object. This way it's easier to
* use if the declaration object of the base class is not available.
*/
template <class X, class B, class Adapted = NoAdaptorTag>
class SubClass
: public Class<X, Adapted>
{
public:
SubClass (const std::string &name, const Methods &mm, const std::string &doc = std::string ())
: Class<X, Adapted> (name, mm, doc)
{
// .. nothing yet ..
}
SubClass (const std::string &name, const std::string &doc = std::string ())
: Class<X, Adapted> (name, doc)
{
// .. nothing yet ..
}
virtual bool consolidate () const
{
// TODO: ugly const_cast
SubClass<X, B, Adapted> *non_const_this = const_cast<SubClass<X, B, Adapted> *> (this);
non_const_this->set_base (cls_decl<B> ());
return Class<X, Adapted>::consolidate ();
}
};
/**
* @brief The declaration of a child class
*
* This declaration is similar to the gsi::Class declaration but makes the given class
* a subclass of the parent.
*/
template <class P, class X, class Adapted = NoAdaptorTag>
class ChildClass
: public Class<X, Adapted>
{
public:
ChildClass (const std::string &name, const Methods &mm, const std::string &doc = std::string ())
: Class<X, Adapted> (name, mm, doc)
{
// .. nothing yet ..
}
ChildClass (const std::string &name, const std::string &doc = std::string ())
: Class<X, Adapted> (name, doc)
{
// .. nothing yet ..
}
virtual bool consolidate () const
{
// TODO: ugly const cast
ClassBase *non_const_pcls = const_cast<ClassBase *> (cls_decl<P> ());
non_const_pcls->add_child_class (this);
return Class<X, Adapted>::consolidate ();
}
};
/**
* @brief The declaration of a subclass with a base class
*
* This declaration is similar to the gsi::Class declaration but makes the given class
* a subclass of the parent.
*/
template <class P, class X, class B, class Adapted = NoAdaptorTag>
class ChildSubClass
: public SubClass<X, B, Adapted>
{
public:
ChildSubClass (const std::string &name, const Methods &mm, const std::string &doc = std::string ())
: SubClass<X, B, Adapted> (name, mm, doc)
{
// .. nothing yet ..
}
ChildSubClass (const std::string &name, const std::string &doc = std::string ())
: SubClass<X, B, Adapted> (name, doc)
{
// .. nothing yet ..
}
virtual bool consolidate () const
{
// TODO: ugly const cast
ClassBase *non_const_pcls = const_cast<ClassBase *> (cls_decl<P> ());
non_const_pcls->add_child_class (this);
return SubClass<X, B, Adapted>::consolidate ();
}
};
/**
* @brief Produce a fallback class declaration
*
* The main intention of this function is to provide a warning message
* for development.
*/
GSI_PUBLIC const ClassBase *fallback_cls_decl (const std::type_info &ti);
/**
* @brief Obtain the class declaration for a given class
*
* This method looks up the declaration object for a given type.
* It does so dynamically, since declarations may be located in different
* libraries. However, for performance reasons, the definitions are cached.
*/
template <class X>
const ClassBase *cls_decl ()
{
// TODO: needs thread safety? It's rather unlikely that two threads enter this
// 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;
}
}
if (!cd) {
cd = fallback_cls_decl (typeid (X));
}
}
return cd;
}
}
#endif