new
This commit is contained in:
@@ -0,0 +1,420 @@
|
||||
/*
|
||||
PLIB - A Suite of Portable Game Libraries
|
||||
Copyright (C) 1998,2002 Steve Baker
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
For further information visit http://plib.sourceforge.net */
|
||||
|
||||
|
||||
/*
|
||||
Originally written by: Alexandru C. Telea <alext@win.tue.nl>
|
||||
*/
|
||||
|
||||
/*
|
||||
This file provides support for RTTI and generalized (virtual-base to derived
|
||||
and separate hierarchy branches) casting. There is also support for RT obj
|
||||
creation from type names.
|
||||
|
||||
In order to enable these features for a class, two things should be done:
|
||||
|
||||
1) insert the text UL_TYPE_DATA (without ';') in the class-decl.
|
||||
2) in the .C file where the class's implementation resides, insert the
|
||||
following (without';'):
|
||||
|
||||
UL_RTTI_DEF(classname)
|
||||
if the class has no bases with RTTI
|
||||
|
||||
UL_RTTI_DEFn(classname,b1,...bn)
|
||||
if the class has bases b1,...bn with RTTI
|
||||
|
||||
Use UL_RTTI_DEF_INST instead of UL_RTTI_DEF if you want to enable RT
|
||||
obj creation for classname. You should provide then a public default
|
||||
ctor.
|
||||
|
||||
RTTI is used via a class called ulRTTItypeid. A typeid describes a type of a
|
||||
class. [..] They should provide all necessary support for any kind of
|
||||
RTTI/casting [..].
|
||||
|
||||
[..]
|
||||
|
||||
REMARK: There are two classes related to RTTI: ulRTTItypeid and
|
||||
======= ulRTTITypeinfo. A ulRTTItypeid is, as it says, an 'id for a
|
||||
type'. It actually wraps a ulRTTITypeinfo*, where a
|
||||
ulRTTITypeinfo contains the actual encoding of a class type.
|
||||
You can freely create/copy/destroy/manipulate ulRTTItypeid's,
|
||||
but you should NEVER deal directly with ulRTTITypeinfo. A
|
||||
ulRTTITypeinfo should actually be created ONLY by the
|
||||
UL_TYPE_DATA macros, as part of a class definition, since the
|
||||
ulRTTITypeinfo encodes a type info for an EXISTING class [..].
|
||||
All type-related stuff should be therefore handled via
|
||||
ulRTTItypeid's.
|
||||
*/
|
||||
|
||||
#ifndef _UL_RTTI_H_
|
||||
#define _UL_RTTI_H_
|
||||
|
||||
#include <string.h>
|
||||
#include "ul.h"
|
||||
|
||||
|
||||
class ulRTTITypeinfo
|
||||
/* Implementation of type-related info */
|
||||
{
|
||||
private:
|
||||
|
||||
char *n ; /* type name */
|
||||
|
||||
/*
|
||||
base types (NULL-ended array of ulRTTITypeinfo's for this's direct bases)
|
||||
*/
|
||||
const ulRTTITypeinfo** b ;
|
||||
|
||||
int ns ; /* #subtypes of this type */
|
||||
const ulRTTITypeinfo **subtypes ; /* types derived from this type */
|
||||
|
||||
/* convenience type info for a 'null' type */
|
||||
static const ulRTTITypeinfo null_type ;
|
||||
|
||||
void* (*new_obj)() ; /* func to create a new obj of this type */
|
||||
void* (*cast)(int,void*) ; /*
|
||||
func to cast an obj of this type to ith
|
||||
baseclass of it or to itself
|
||||
*/
|
||||
|
||||
/* adds a subtype to this's subtypes[] */
|
||||
void add_subtype ( const ulRTTITypeinfo * ) ;
|
||||
|
||||
/* dels a subtype from this's subtypes[] */
|
||||
void del_subtype ( const ulRTTITypeinfo* ) ;
|
||||
|
||||
friend class ulRTTItypeid ; /* for null_type */
|
||||
|
||||
public:
|
||||
|
||||
ulRTTITypeinfo ( const char* name, const ulRTTITypeinfo* bb[],
|
||||
void* (*)(int,void*),void* (*)() ) ;
|
||||
~ulRTTITypeinfo () ;
|
||||
|
||||
/* Returns name of this ulRTTITypeinfo */
|
||||
const char* getname () const { return n ; }
|
||||
|
||||
/* Compares 2 ulRTTITypeinfo objs */
|
||||
bool same ( const ulRTTITypeinfo *p ) const
|
||||
{
|
||||
/*
|
||||
First, try to see if it's the same 'physical' ulRTTITypeinfo (which
|
||||
should be the case, since we create them per-class and not per-obj).
|
||||
*/
|
||||
return ( this == p ) || !strcmp ( n, p->n ) ;
|
||||
}
|
||||
|
||||
/* true if the arg can be cast to this, else false */
|
||||
bool can_cast ( const ulRTTITypeinfo *p ) const
|
||||
{
|
||||
return same ( p ) || p->has_base ( this ) ;
|
||||
}
|
||||
|
||||
/* true if this has the arg as some base, else false */
|
||||
bool has_base ( const ulRTTITypeinfo *p ) const
|
||||
{
|
||||
for ( int i = 0 ; b[i] != NULL ; i++ ) /* for all bases of this... */
|
||||
/* match found, return 1 or no match, search deeper */
|
||||
if ( p->same ( b[i] ) || b[i]->has_base ( p ) ) return true ;
|
||||
return false ; /* no match at all, return false */
|
||||
}
|
||||
|
||||
/* get i-th subclass of this, if any, else NULL */
|
||||
const ulRTTITypeinfo * subclass ( int i = 0 ) const
|
||||
{
|
||||
return ( i >= 0 && i < ns ) ? subtypes[i] : NULL ;
|
||||
}
|
||||
|
||||
int num_subclasses () const { return ns ; } /* get # subclasses of this */
|
||||
|
||||
/*
|
||||
search for a subclass named char*, create obj of it and return it cast to
|
||||
the ulRTTITypeinfo* type, which is either this or a direct base of this.
|
||||
*/
|
||||
void * create ( const ulRTTITypeinfo *, const char * ) const ;
|
||||
|
||||
/* Returns true if this type has a default ctor, else false */
|
||||
bool can_create () const { return new_obj != NULL ; }
|
||||
} ;
|
||||
|
||||
|
||||
class ulRTTItypeid
|
||||
/* Main class for RTTI interface */
|
||||
{
|
||||
protected:
|
||||
|
||||
/* ulRTTItypeid implementation (the only data-member) */
|
||||
const ulRTTITypeinfo* id ;
|
||||
|
||||
public:
|
||||
|
||||
/* Not for application use ! */
|
||||
const ulRTTITypeinfo* get_info () const { return id ; }
|
||||
|
||||
ulRTTItypeid ( const ulRTTITypeinfo* p ) : id ( p ) { }
|
||||
ulRTTItypeid () : id ( &ulRTTITypeinfo::null_type ) { }
|
||||
|
||||
/* Compares 2 ulRTTItypeid objs */
|
||||
bool isSame ( ulRTTItypeid i ) const { return id->same ( i.id ) ; }
|
||||
|
||||
/* true if the arg can be cast to this, else false */
|
||||
bool canCast ( ulRTTItypeid i ) const { return id->can_cast ( i.id ) ; }
|
||||
|
||||
const char * getName () const { return id->getname () ; }
|
||||
|
||||
/* Return # subclasses of this */
|
||||
int getNumSubclasses () const { return id->num_subclasses () ; }
|
||||
|
||||
/* Return ith subclass of this */
|
||||
ulRTTItypeid getSubclass ( int i ) const { return id->subclass ( i ) ; }
|
||||
|
||||
/* Return # baseclasses of this */
|
||||
int getNumBaseclasses () const
|
||||
{
|
||||
int i ; for ( i = 0 ; id->b[i] != NULL ; i++ ) ;
|
||||
return i ;
|
||||
}
|
||||
|
||||
/* Return ith baseclass of this */
|
||||
ulRTTItypeid getBaseclass ( int i ) const { return id->b[i] ; }
|
||||
|
||||
/*
|
||||
Tries to create an instance of a subclass of this having of type given
|
||||
by the ulRTTItypeid arg. If ok, it returns it casted to the class-type of
|
||||
this and then to void*
|
||||
*/
|
||||
void * create ( ulRTTItypeid t ) const
|
||||
{
|
||||
return id->create ( id, t.getName () ) ;
|
||||
}
|
||||
|
||||
/* Returns true if this type is instantiable, else false */
|
||||
bool canCreate () const { return id->can_create () ; }
|
||||
} ;
|
||||
|
||||
|
||||
class ulRTTIdyntypeid : public ulRTTItypeid
|
||||
/*
|
||||
Class for dynamic type creation from user strings. Useful for creating
|
||||
typeids at RT for comparison purposes.
|
||||
*/
|
||||
{
|
||||
private:
|
||||
|
||||
static const ulRTTITypeinfo *a[] ;
|
||||
|
||||
public:
|
||||
|
||||
ulRTTIdyntypeid ( const char *c ) :
|
||||
/* create a dummy ulRTTITypeinfo */
|
||||
ulRTTItypeid ( new ulRTTITypeinfo ( c, a, NULL, NULL ) ) { }
|
||||
|
||||
~ulRTTIdyntypeid () { delete id ; /* delete the dummy ulRTTITypeinfo */ }
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Macros
|
||||
*/
|
||||
|
||||
/*
|
||||
'ulRTTItypeid'
|
||||
UL_STATIC_TYPE_INFO(T) T=RTTI-class name.
|
||||
Returns a ulRTTItypeid with T's type. If T
|
||||
hasn't RTTI, a compile-time error occurs.
|
||||
*/
|
||||
|
||||
#define UL_STATIC_TYPE_INFO(T) T::RTTI_sinfo()
|
||||
|
||||
|
||||
/*
|
||||
'T*'
|
||||
UL_PTR_CAST(T,p) T=RTTI-class, p=RTTI-class ptr.
|
||||
Returns p cast to the type T as a T*, if cast is
|
||||
possible, else returns NULL. If *p or T have no RTTI,
|
||||
a compile-time error occurs. Note that p can point to
|
||||
virtual base classes. Casting between separat branches
|
||||
of a class hierarchy is also supported, as long as all
|
||||
classes have RTTI. Therefore UL_PTR_CAST is a fully
|
||||
general and safe operator. If p==NULL, the operator
|
||||
returns NULL.
|
||||
*/
|
||||
|
||||
#define UL_PTR_CAST(T,p) ((p != NULL)? (T*)((p)->RTTI_cast(UL_STATIC_TYPE_INFO(T))) : NULL)
|
||||
|
||||
|
||||
/* 'T*'
|
||||
UL_TYPE_NEW(T,t) T=RTTI-class, t=ulRTTItypeid
|
||||
Returns a new object of type t cast to the type T as
|
||||
a T*. t must represent a type identical to or derived
|
||||
from T. If t is not a type derived from T or not an
|
||||
instantiable type having a default constructor, NULL is
|
||||
returned. */
|
||||
|
||||
#define UL_TYPE_NEW(T,t) ((T*)t.create(T))
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Definition of TYPE_DATA for a RTTI-class: introduces one static
|
||||
ulRTTITypeinfo data-member and a couple of virtuals.
|
||||
*/
|
||||
|
||||
#define UL_TYPE_DATA \
|
||||
protected: \
|
||||
static const ulRTTITypeinfo RTTI_obj; \
|
||||
static void* RTTI_scast(int,void*); \
|
||||
static void* RTTI_new(); \
|
||||
virtual ulRTTItypeid RTTI_vinfo() const { return &RTTI_obj; }\
|
||||
public: \
|
||||
static ulRTTItypeid RTTI_sinfo() { return &RTTI_obj; }\
|
||||
virtual void* RTTI_cast(ulRTTItypeid);
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Definition of auxiliary data-structs supporting RTTI for a class: defines
|
||||
the static ulRTTITypeinfo object of that class and its associated virtuals.
|
||||
*/
|
||||
|
||||
/* Auxiliary definition of the construction method: */
|
||||
#define UL_RTTI_NEW(cls) void* cls::RTTI_new() { return new cls; } \
|
||||
const ulRTTITypeinfo cls::RTTI_obj(#cls,RTTI_base_ ## cls,cls::RTTI_scast,cls::RTTI_new);
|
||||
|
||||
#define UL_RTTI_NO_NEW(cls) const ulRTTITypeinfo cls::RTTI_obj(#cls,RTTI_base_ ## cls,cls::RTTI_scast,NULL);
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Top-level macros:
|
||||
*/
|
||||
|
||||
#define UL_RTTI_DEF_BASE(cls) \
|
||||
static const ulRTTITypeinfo* RTTI_base_ ## cls [] = { NULL }; \
|
||||
void* cls::RTTI_cast(ulRTTItypeid t) \
|
||||
{ \
|
||||
if (t.isSame(&RTTI_obj)) return this; \
|
||||
return NULL; \
|
||||
} \
|
||||
void* cls::RTTI_scast(int i,void* p) \
|
||||
{ cls* ptr = (cls*)p; return ptr; }
|
||||
|
||||
|
||||
#define UL_RTTI_DEF1_BASE(cls,b1) \
|
||||
static const ulRTTITypeinfo* RTTI_base_ ## cls [] = \
|
||||
{ UL_STATIC_TYPE_INFO(b1).get_info(), NULL }; \
|
||||
void* cls::RTTI_cast(ulRTTItypeid t) \
|
||||
{ \
|
||||
if (t.isSame(&RTTI_obj)) return this; \
|
||||
void* ptr; \
|
||||
if ((ptr=b1::RTTI_cast(t))) return ptr; \
|
||||
return NULL; \
|
||||
} \
|
||||
void* cls::RTTI_scast(int i,void* p) \
|
||||
{ cls* ptr = (cls*)p; \
|
||||
switch(i) \
|
||||
{ case 0: return (b1*)ptr; } \
|
||||
return ptr; \
|
||||
}
|
||||
|
||||
|
||||
#define UL_RTTI_DEF2_BASE(cls,b1,b2) \
|
||||
static const ulRTTITypeinfo* RTTI_base_ ## cls [] = \
|
||||
{ UL_STATIC_TYPE_INFO(b1).get_info(), \
|
||||
UL_STATIC_TYPE_INFO(b2).get_info(), NULL }; \
|
||||
void* cls::RTTI_cast(ulRTTItypeid t) \
|
||||
{ \
|
||||
if (t.isSame(&RTTI_obj)) return this; \
|
||||
void* ptr; \
|
||||
if ((ptr=b1::RTTI_cast(t))) return ptr; \
|
||||
if ((ptr=b2::RTTI_cast(t))) return ptr; \
|
||||
return NULL; \
|
||||
} \
|
||||
void* cls::RTTI_scast(int i,void* p) \
|
||||
{ cls* ptr = (cls*)p; \
|
||||
switch(i) \
|
||||
{ case 0: return (b1*)ptr; \
|
||||
case 1: return (b2*)ptr; \
|
||||
} \
|
||||
return ptr; \
|
||||
}
|
||||
|
||||
#define UL_RTTI_DEF3_BASE(cls,b1,b2,b3) \
|
||||
static const ulRTTITypeinfo* RTTI_base_ ## cls [] = \
|
||||
{ UL_STATIC_TYPE_INFO(b1).get_info(), \
|
||||
UL_STATIC_TYPE_INFO(b2).get_info(), \
|
||||
UL_STATIC_TYPE_INFO(b3).get_info(), NULL }; \
|
||||
void* cls::RTTI_cast(ulRTTItypeid t) \
|
||||
{ \
|
||||
if (t.isSame(&RTTI_obj)) return this; \
|
||||
void* ptr; \
|
||||
if ((ptr=b1::RTTI_cast(t))) return ptr; \
|
||||
if ((ptr=b2::RTTI_cast(t))) return ptr; \
|
||||
if ((ptr=b3::RTTI_cast(t))) return ptr; \
|
||||
return NULL; \
|
||||
} \
|
||||
void* cls::RTTI_scast(int i,void* p) \
|
||||
{ cls* ptr = (cls*)p; \
|
||||
switch(i) \
|
||||
{ case 0: return (b1*)ptr; \
|
||||
case 1: return (b2*)ptr; \
|
||||
case 2: return (b3*)ptr; \
|
||||
} \
|
||||
return ptr; \
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define UL_RTTI_DEF_INST(cls) \
|
||||
UL_RTTI_DEF_BASE(cls) \
|
||||
UL_RTTI_NEW(cls)
|
||||
|
||||
#define UL_RTTI_DEF(cls) \
|
||||
UL_RTTI_DEF_BASE(cls) \
|
||||
UL_RTTI_NO_NEW(cls)
|
||||
|
||||
#define UL_RTTI_DEF1_INST(cls,b1) \
|
||||
UL_RTTI_DEF1_BASE(cls,b1) \
|
||||
UL_RTTI_NEW(cls)
|
||||
|
||||
#define UL_RTTI_DEF1(cls,b1) \
|
||||
UL_RTTI_DEF1_BASE(cls,b1) \
|
||||
UL_RTTI_NO_NEW(cls)
|
||||
|
||||
#define UL_RTTI_DEF2_INST(cls,b1,b2) \
|
||||
UL_RTTI_DEF2_BASE(cls,b1,b2) \
|
||||
UL_RTTI_NEW(cls)
|
||||
|
||||
#define UL_RTTI_DEF2(cls,b1,b2) \
|
||||
UL_RTTI_DEF2_BASE(cls,b1,b2) \
|
||||
UL_RTTI_NO_NEW(cls)
|
||||
|
||||
#define UL_RTTI_DEF3_INST(cls,b1,b2,b3) \
|
||||
UL_RTTI_DEF3_BASE(cls,b1,b2,b3) \
|
||||
UL_RTTI_NEW(cls)
|
||||
|
||||
#define UL_RTTI_DEF3(cls,b1,b2,b3) \
|
||||
UL_RTTI_DEF3_BASE(cls,b1,b2,b3) \
|
||||
UL_RTTI_NO_NEW(cls)
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user