Big changes

This commit is contained in:
Kirill Yurkin
2025-03-07 16:54:27 +03:00
parent dd05797b95
commit 719171e7d8
21 changed files with 817 additions and 285 deletions

View File

@@ -1,141 +1,66 @@
/*
The other day we tracked a bad bug where a base class was been cast to
the wrong thing.
The reason why it happed was because we didn't have any RTTI (Run Time
Type Information) in place.
We also didn't want to use the one that it comes with the compiler for
fear that it will add "evil" code.
So after hitting that bug I decided to do my on RTTI. I wanted to be
simple and very fast.
This is what we use now. It looks kind of neat so I thought to share it.
Enjoy.
Tomas
tarce@zen-x.net
*/
#ifndef RTTI_H
#define RTTI_H
#include <stdlib.h>
#include <assert.h>
#include <string.h>
//==============================================================================
// RTTI
//==============================================================================
// Using the RTTI
//------------------------------------------------------------------------------
// struct base
// {
// CREATE_RTTI_BASE( base );
// };
//
// struct pepe : public base
// {
// CREATE_RTTI( pepe, base, base )
// void Normal( void ){}
// };
//
// struct super_pepe : public pepe
// {
// CREATE_RTTI( super_pepe, pepe, base )
// void Super( void ){}
// };
//
// void main( void )
// {
// super_pepe SP; // The original class
// base& B = SP; // Some generic base reference
//
// // We want to safely convert to pepe
// pepe& P = pepe::GetSaveType( B );
//
// // cast the base class right
// if( B.IsKindOf( super_pepe::GetRTTI() ) )
// {
// super_pepe& SP = super_pepe::GetSaveType( B );
// SP.Super();
// }
// else if( B.IsKindOf( pepe::GetRTTI() ) )
// {
// pepe& P = pepe::GetSaveType( B );
// P.Normal();
// }
// }
//==============================================================================
#define CREATE_RTTI( TYPE, BASE_CLASS )
#define CREATE_RTTI_BASE( TYPE )
struct RTTI
struct RuntimeClass
{
bool IsKindOf( const RTTI& RTTI ) const;
RTTI ( const char* pTypeName );
RTTI ( const char* pTypeName, const RTTI& RTTI );
const char* pType; // This is not really need it, just useful in debugger.
const RTTI& Next;
bool IsKindOf(const RuntimeClass* pRuntimeClass) const;
RuntimeClass(const char* pClassName);
RuntimeClass(const char* pClassName, const RuntimeClass* pBaseClass);
const char* m_pClassName;
const RuntimeClass* m_pBaseClass;
};
#define DECLARE_RTTI \
static RuntimeClass ms_RuntimeClass; \
virtual RuntimeClass* GetRuntimeClass() \
{ \
return &ms_RuntimeClass; \
}
#define IMPLEMENT_RTTI_BASE( Class ) \
RuntimeClass Class::ms_RuntimeClass( #Class ) \
#define IMPLEMENT_RTTI( Class, BaseClass ) \
RuntimeClass Class::ms_RuntimeClass( #Class, &BaseClass::ms_RuntimeClass ) \
//==============================================================================
// IMPLEMENTATION
//==============================================================================
#pragma warning( push )
#pragma warning( disable : 4355 ) // warning 'this' used in base member initializer list
#undef CREATE_RTTI
#undef CREATE_RTTI_BASE
inline RuntimeClass::RuntimeClass( const char* pClassName) :
m_pClassName(pClassName), m_pBaseClass( NULL ){}
inline RTTI::RTTI( const char* pTypeName ) :
pType(pTypeName), Next( *this ){}
inline RuntimeClass::RuntimeClass( const char* pClassName, const RuntimeClass* pBaseClass ) :
m_pClassName(pClassName), m_pBaseClass( pBaseClass ){}
inline RTTI::RTTI( const char* pTypeName, const RTTI& RTTI ) :
pType(pTypeName), Next( RTTI ){}
inline bool RTTI::IsKindOf( const RTTI& RTTI ) const
inline bool RuntimeClass::IsKindOf( const RuntimeClass* pRuntimeClass ) const
{
const RTTI* p = this;
do
{
if( p == &RTTI ) return true;
if( p == &p->Next ) break;
p = &p->Next;
} while(1);
const RuntimeClass* p = this;
while (p)
{
if ( p == pRuntimeClass )
return true;
p = p->m_pBaseClass;
}
return false;
}
#define PRIVATE_RTTI_FUNCTION_SET( TYPE, BASE_CLASS ) \
virtual inline const RTTI& GetObjectRTTI( void ) const \
{ \
return TYPE::GetRTTI(); \
} \
inline const bool IsKindOf( const RTTI& RTTI ) const \
{ \
return GetObjectRTTI().IsKindOf( RTTI ); \
} \
static inline TYPE& GetSaveType( BASE_CLASS& Object ) \
{ \
assert( Object.IsKindOf(TYPE::GetRTTI()) ); \
return *((TYPE*)&Object); \
} \
static inline const TYPE& GetSaveType( const BASE_CLASS& Object ) \
{ \
assert( Object.IsKindOf(TYPE::GetRTTI()) ); \
return *((const TYPE*)&Object); \
}
#define CREATE_RTTI( TYPE, TYPE_PARENT, BASE_CLASS ) \
static inline const RTTI& GetRTTI( void ) \
{ \
static RTTI s_RTTI( #TYPE, TYPE_PARENT::GetRTTI() ); \
return s_RTTI; \
} \
PRIVATE_RTTI_FUNCTION_SET(TYPE,BASE_CLASS)
#define CREATE_RTTI_BASE( TYPE ) \
static inline const RTTI& GetRTTI( void ) \
{ \
static RTTI s_RTTI( #TYPE ); \
return s_RTTI; \
} \
PRIVATE_RTTI_FUNCTION_SET(TYPE,TYPE)
#pragma warning( pop )
template <typename T, typename C>
T* DynamicCast(C* pObj)
{
if ( pObj->GetRuntimeClass()->IsKindOf( &T::ms_RuntimeClass ) )
return (T*)pObj;
return 0;
}
#endif // !RTTI_H