Poor man's RTTI is mostly gone.
Some checks failed
CI / ubuntu-latest-html-tests (push) Has been cancelled
CI / ubuntu-latest-no-tls (push) Has been cancelled
CI / ubuntu-latest-mbedtls2 (push) Has been cancelled
CI / ubuntu-latest-openssl-3 (push) Has been cancelled
CI / ubuntu-latest-with-old-std (push) Has been cancelled
CI / ubuntu-20-04-openssl-1-1 (push) Has been cancelled
CI / alpine-mbedtls-3_6_0 (push) Has been cancelled
CI / macOS-13-openssl-1-1 (push) Has been cancelled
CI / macOS-13-openssl-3 (push) Has been cancelled
CI / freebsd-14-openssl-3 (push) Has been cancelled
CI / windows-mbedtls (push) Has been cancelled

I'm keeping the type-index to name mapping, for now.
This commit is contained in:
2025-08-09 06:31:08 -04:00
parent f69784c518
commit 8549ca489f
26 changed files with 27 additions and 216 deletions

View File

@ -24,47 +24,7 @@
namespace lout {
namespace identity {
// ------------------------
// IdentifiableObject
// ------------------------
using namespace object;
using namespace container::typed;
IdentifiableObject::Class::Class (IdentifiableObject::Class *parent, const std::type_index id,
const char *className)
: id( (std::intptr_t) id.name() )
{
this->parent = parent;
this->className = className;
}
void IdentifiableObject::Class::intoStringBuffer(misc::StringBuffer *sb)
{
sb->append ("<class ");
sb->append (className);
sb->append (" (");
sb->appendInt (id);
sb->append (")");
if (parent) {
sb->append (", parent: ");
parent->intoStringBuffer (sb);
}
sb->append (">");
}
std::map< std::string, std::unique_ptr< IdentifiableObject::Class > > IdentifiableObject::classesByName;
std::map< std::intptr_t, IdentifiableObject::Class * > IdentifiableObject::classesById;
IdentifiableObject::Class *IdentifiableObject::currentlyConstructedClass;
IdentifiableObject::IdentifiableObject ()
{
currentlyConstructedClass = NULL;
}
std::map< std::type_index, std::string > IdentifiableObject::classNames;
void IdentifiableObject::intoStringBuffer(misc::StringBuffer *sb)
{
@ -76,23 +36,12 @@ void IdentifiableObject::intoStringBuffer(misc::StringBuffer *sb)
}
/**
* \brief This method must be called in the constructor for the sub class.
* See class comment for details.
* Register a name for a class.
*/
void IdentifiableObject::registerName (const char *className, const std::type_index index, std::intptr_t *classId)
void
IdentifiableObject::registerName( const char *const className, const std::type_index index )
{
if (not classesByName.contains( className )) {
classesByName.emplace( className,
std::make_unique< Class >( currentlyConstructedClass, index, className ) );
auto *const klass= classesByName.at( className ).get();
classesById[ klass->id ]= klass;
*classId = klass->id;
}
Class *const klass = classesByName.at( className ).get();
this->classId = klass->id;
*classId = klass->id;
currentlyConstructedClass = klass;
classNames.insert( { index, className } );
}
} // namespace identity

View File

@ -15,127 +15,35 @@
namespace lout {
/**
* \brief Some stuff to identify classes of objects at run-time.
* \brief This was a poor man's RTTI implementation.
*/
namespace identity {
/**
* \brief Instances of classes, which are sub classes of this class, may
* be identified at run-time.
* Hooks for class name inspection.
*
* <h3>Testing the class</h3>
* It began life as an RTTI clone. It did not support multiple inheritance.
*
* Since e.g. dw::Textblock is a sub class of IdentifiableObject, and
* implemented in the correct way (as described below), for any given
* IdentifiableObject the following test can be done:
*
* \code
* identity::IdentifiableObject *o;
* // ...
* bool isATextblock = o->instanceOf(dw::Textblock::CLASS_ID);
* \endcode
*
* \em isATextblock is true, when \em o is an instance of dw::Textblock,
* or of a sub class of dw::Textblock. Otherwise, \em isATextblock is false.
*
* It is also possible to get the class identifier of an
* identity::IdentifiableObject, e.g.
*
* \code
* bool isOnlyATextblock = o->getClassId() == dw::Textblock::CLASS_ID;
* \endcode
*
* would result in true, if o is an instance of dw::Textblock, but not an
* instance of a sub class of dw::Textblock.
*
* <h3>Defining Sub Classes</h3>
*
* Each direct or indirect sub class of IdentifiableObject must
*
* <ul>
* <li> add a static int CLASS_ID with -1 as initial value, and
* <li> call registerName (\em name, &CLASS_ID) in the constructor, where
* \em name should be unique, e.g. the fully qualified class name.
* </ul>
*
* After this, <i>class</i>\::CLASS_ID refers to a number, which denotes the
* class. (If this is still -1, since the class has not yet been instantiated,
* any test will fail, which is correct.)
*
* <h3>Notes on implementation</h3>
*
* If there are some classes like this:
*
* \dot
* digraph G {
* node [shape=record, fontname=Helvetica, fontsize=10];
* edge [arrowhead="none", arrowtail="empty", labelfontname=Helvetica,
* labelfontsize=10, color="#404040", labelfontcolor="#000080"];
* fontname=Helvetica; fontsize=10;
* IdentifiableObject [color="#a0a0a0"];
* A;
* B [color="#a0a0a0"];
* C;
* IdentifiableObject -> A;
* IdentifiableObject -> B;
* B -> C;
* }
* \enddot
*
* <center>[\ref uml-legend "legend"]</center>
*
* and first, an instance of A, and then an instance of C is created, there
* will be the following calls of functions and constructors:
*
* <ol>
* <li> %IdentifiableObject ();
* <li> %registerName ("A", &A::CLASS_ID);
* <li> %IdentifiableObject ();
* <li> %registerName ("B", &B::CLASS_ID);
* <li> %registerName ("C", &C::CLASS_ID);
* </ol>
*
* From this, the class hierarchy above can easily constructed, and stored
* in identity::IdentifiableObject::classesByName and
* in identity::IdentifiableObject::classesById. See the code for details.
*
* N.b. Multiple inheritance is not supported, the construction of the
* tree would become confused.
* It appeared to be a model of Java's `Object` system. It's mostly been migrated
* to use C++ RTTI and most use cases should be avoiding the `lout::contaner` stuff.
*/
class IdentifiableObject: public object::Object
{
private:
class Class final: public object::Object
{
public:
Class *parent;
std::intptr_t id;
const char *className;
Class (Class *parent, std::type_index id, const char *className);
void intoStringBuffer(misc::StringBuffer *sb);
};
static std::map< std::string, std::unique_ptr< Class > > classesByName;
static std::map< std::intptr_t, Class * > classesById;
static Class *currentlyConstructedClass;
std::intptr_t classId;
// TODO: Use the Alepha facility for this, eventually...
static std::map< std::type_index, std::string > classNames;
protected:
void registerName (const char *className, std::type_index index, std::intptr_t *classId);
void registerName (const char *className, std::type_index index);
public:
IdentifiableObject ();
void intoStringBuffer(misc::StringBuffer *sb);
void intoStringBuffer(misc::StringBuffer *sb) override;
/**
* \brief Return the name, under which the class of this object was
* registered.
*/
const char *getClassName() { return classesById.at( classId )->className; }
const char *getClassName() { return classNames.at( typeid( *this ) ).c_str(); }
};
} // namespace identity