Monday 12 November 2007

RTTI : How to import and export interfaces from classes in a cheap and easy way

Hi,

I have been working on this for some time and tried different solutions but this one I am posting here is the one I like the most. It has some problems tho, as it does not work for DLL's unless you ask the DLL itself for the interface you are requesting, but in the general case, it is very simple to use and does not add any runtime cost (apart from a small amount of memory for each interface type).

Here is the code (I have formatted it a bit to fit into the blog, but I can send you the original file upon request to my email address)

That's all for now!

Cheers!

J.

//****************************************************************************
// Templatized RTTI
// Date(dd/mm/yyy): 22/06/2007
// Author: Jaime C. Olivares - cherno.olivares#gmailDOTYOUKNOW
//****************************************************************************

#ifndef _NW_RTTI_H_
#define _NW_RTTI_H_

typedef intptr_t NWRttiTypeId;

//----------------------------------------------------------------------------
// The RTTI itself
// It is a simple idea:
// The address of a static member of a templatized class
//----------------------------------------------------------------------------
template '<'class T'>' class NWRtti
{
public:
static inline NWRttiTypeId getTypeId();

private:
static int mDummyVar;
};

template '<'class T'>' /*static*/ int NWRtti'<'T'>'::mDummyVar = 0;

template '<'class T'>' /*static*/ inline NWRttiTypeId NWRtti'<'T'>'::getTypeId()
{
// avoids compiler to optimize and return same addr for all types
++mDummyVar;

// return the address of this member fn as RTTI
return (NWRttiTypeId)&getTypeId;
}

#define RTTI_TYPE_ID(T) static inline NWRttiTypeId getTypeId() \
{return NWRtti'<'T'>'::getTypeId();} // use this macro to have TypeId in classes

//----------------------------------------------------------------------------
// Helper class to inherit from by classes exporting interfaces
//----------------------------------------------------------------------------
class NWInterfaceProvider
{
public:
NWInterfaceProvider() {}
virtual ~NWInterfaceProvider() {}

template '<'class T'>' inline T * getInterface();

protected:
//derived classes must implement this fn
virtual void * getInterfaceFromID(NWRttiTypeId _typeId)=0;

template '<'class T'>' inline T * NWInterfaceProvider::getInterface()
{
return (T *) getInterfaceFromID(NWRtti'<'T'>'::getTypeId());
}

#endif //_NW_RTTI_H_

//****************************************************************************
// Example
//****************************************************************************

//----------------------------------------------------------------------------
// Some interfaces we want share
//----------------------------------------------------------------------------
//struct IEncoder
//{
// virtual unsigned int getEncodingCaps()=0;
// ...
//
// RTTI_TYPE_ID(IEncoder)
//};
//
//struct IVideoEncoder
//{
// virtual unsigned int getVideoEncoderCaps()=0;
// ...
//
// RTTI_TYPE_ID(IVideoEncoder)
//}
//
//struct IVideoEncoderH264
//{
// virtual int getVideoCodecH264KeyFramePeriod()=0;
// ...
//
// RTTI_TYPE_ID(IVideoEncoderH264)
//}

//----------------------------------------------------------------------------
// The exporter (or it's base class if any) inherits from NWInterfaceProvider
//----------------------------------------------------------------------------
//class VideoEncoderDicasH264 : public NWInterfaceProvider
//{
//public:
// ...
//
//protected:
// virtual void * getInterfaceFromID(NWRttiTypeId _iid);
// // Implement this fn to provide the valid interfaces
// //private:
// ...
//};
//----------------------------------------------------------------------------
// Exporter class fn (this class inherits from the interface): //----------------------------------------------------------------------------
// /*virtual*/ void * VideoEncoderDicasH264::getInterfaceFromID(NWRttiTypeId _iid)
//{
// if(_iid == IVideoEncoderH264::getTypeId())
// {
// return static_cast'<'IVideoEncoderH264*'>'(this);
// }
// else if(_iid == IVideoEncoder::getTypeId())
// {
// return static_cast'<'IVideoEncoder*'>'(this);
// }
// else if(_iid == IEncoder::getTypeId())
// {
// return static_cast'<'IEncoder*'>'(this);
// }
//
// return NULL; // if no base class just return NULL or
// //return Inherited::getInterfaceFromID(_iid); // if base class has other interfaces
//}

//----------------------------------------------------------------------------
// External use
//----------------------------------------------------------------------------
//void test()
//{
// VideoEncoderDicasH264 encoderObj;
//
// encoderObj.init();
//
// IEncoder * encoder = encoderObj.getInterface();
// if(encoder)
// {
// unsigned int caps = encoder->getEncodingCaps();
// }
//
// IVideoEncoder * videoEncoder = encoderObj.getInterface'<'IVideoEncoder'>'();
// if(videoEncoder)
// {
// unsigned int caps = videoEncoder->getVideoEncoderCaps();
// }
//
// IVideoEncoderH264 * encH264 = encoderObj.getInterface'<'IVideoEncoderH264'>'();
// if(videoEncoderH264)
// {
// int keyFramePeriod = videoEncoderH264->getVideoCodecH264KeyFramePeriod();
// }
//
// encoderObj.shutdown();
//}

Relocated to Canada, back to business

Hi there,

Here I am, back from some months of virtual absence due to the new job I got at Montreal (Canada).

But now that I have arrived and got my new intertnet connection I am ready to start some posts.

First one to come... RTTI

See u around!


J.

Monday 2 July 2007

This blog is starting... be patient

Dear bloggers,

During the following weeks I'm going to write a bit about real c++ projects I'm working on.
I will cover different programming areas, from GUI to game AI or game architecture.
Some examples that will come soon are :
- A good coding standard
- User resistant init/done pattern
- Dynamic software architecture and tools needed to implement it :
..........- Cheap RTTI
..........- Interfaces, exporting and importing functionality with no type dependencies (apart from the interface itself)
..........- State based machines : Easy and versatile implementation
..........- State stack
..........- Messaging systems, channel or message oriented
..........- Script system for in-game use (to allow data driven designs)
-Some FrontEnd tools
..........- XML based script : A fast and easy script for tools
..........- Class delegates, or how to store and call class member pointers from other classes
..........- Property based Frontend / Gui
..........- Remote Frontend for use at diverse software applications


Try to enjoy the reading as much as I'm going to enjoy writing it!

Some feedback would be appreciated if you are interested on any subject.

Cheers!

Cherno