SingeltonTemplate

Post those lines of code you feel like sharing or find what you require for your project here; or simply use them as tutorials.
Post Reply
sudi
Posts: 1686
Joined: Fri Aug 26, 2005 8:38 pm

SingeltonTemplate

Post by sudi »

Ok i was bored and designed a SingeltonTemplate which doesn't need any modification to the Class or Var that is templated. You could even make the IrrlichtDevice a Singelton.
The Template definition:

Code: Select all

#include <iostream>
#include <irrlicht.h>
#include <assert.h>

template<class A>
class SingeltonTemplate
{
public:
    SingeltonTemplate(A* i = NULL)
    {
        if (RefCounter == 0)
        {
            Instance = i;
        }
        //if (Instance == NULL) //try calling standard constructor...not a good idea
        //Instance = new A();
        assert(Instance != NULL);
        if (AutoRemove)
            RefCounter++;
    }
    SingeltonTemplate(const SingeltonTemplate<A>& singelton)
    {
        if (Instance == NULL) //try calling standard constructor
            Instance = new A();
        assert(Instance != NULL);
        if (AutoRemove)
            RefCounter++;
    }
    ~SingeltonTemplate(void)
    {
        if (AutoRemove && Instance)
            RefCounter--;
        if (RefCounter == 0)
        {
            delete Instance;
            Instance = NULL;
        }
        assert(RefCounter >= 0);
    }
    A* operator->(void)
    {
        return Instance;
    }
    A* operator*(void)
    {
        return Instance;
    }
    const A* operator->(void) const
    {
        return Instance;
    }
    const A* operator*(void) const
    {
        return Instance;
    }
    static void TurnAutoRemoveOff(void)
    {
        AutoRemove = false;
    }
    void Destroy(void)
    {
        AutoRemove = true;

        if (Instance)
            delete Instance;

        Instance = NULL;

        RefCounter = 0;
    }
    const bool Valid(void) const
    {
        if ((RefCounter > 0 || !AutoRemove) && Instance)
            return true;
        return false;
    }
    static int GetRefCount(void)
    {
        return RefCounter;
    }


    SingeltonTemplate& operator=(const SingeltonTemplate<A>& singelton)
    {
        //dunno but i think i don't have to grab the pointer here
    }
protected:
    static A* Instance;
    static int RefCounter;
    static bool AutoRemove;
};
template<class A> A* SingeltonTemplate<A>::Instance = NULL;
template<class A> int SingeltonTemplate<A>::RefCounter = 0;
template<class A> bool SingeltonTemplate<A>::AutoRemove = true;
And a Usage example...i know this is not c++ like and not intended to learn from i just did this to show a pattern where singeltons are actually needed.

Code: Select all

class CEntity;
typedef void (*UpdatePointer)(int timeMs, CEntity& entity);
typedef void (*InitPointer)(CEntity& entity);
typedef void (*TimeEventPointer)(void);

void StandardEntityUpdate(int timeMs, CEntity& entity);

class CEntityData
{
public:
    virtual ~CEntityData(void)
    {
    }
};

class CEntity
{
public:
    CEntity(int id, const irr::c8* type) : EntityID(id), EntityType(type), UpdateEntity(&StandardEntityUpdate), Data(NULL)
    {
    }
    CEntity(const CEntity& entity) : EntityID(entity.getEntityID()), EntityType(entity.EntityType), UpdateEntity(entity.UpdateEntity), Data(NULL)
    {
    }
    CEntity& operator=(const CEntity& entity)
    {
        EntityID = entity.getEntityID();
        UpdateEntity = entity.UpdateEntity;
        Data = entity.Data;
        EntityType = entity.EntityType;
        return *this;
    }
    const int& getEntityID(void) const
    {
        return EntityID;
    }

    void setEntityData(CEntityData* data)
    {
        Data = data;
    }

    CEntityData* getEntityData(void)
    {
        return Data;
    }

    const CEntityData* getEntityData(void) const
    {
        return Data;
    }

    UpdatePointer UpdateEntity;
    InitPointer Destructor;
protected:
    int EntityID;
    CEntityData* Data;
    irr::core::stringc EntityType;
};

void StandardEntityUpdate(int timeMs, CEntity& entity)
{
    std::cout<<"Entity["<<entity.getEntityID()<<"] Time: "<<timeMs<<std::endl;
}

class CGameEngine
{
public:
    CGameEngine(void)
    {
        LastEntityID = 0;
        Device = irr::createDevice(irr::video::EDT_OPENGL);
    }

    ~CGameEngine(void)
    {
        Device->drop();
    }

    void RegisterInit(const irr::c8* name, InitPointer init, InitPointer desctruct)
    {
        for (int i=0;i<InitEntities.size();i++)
        {
            if (InitEntities[i].Name == name)
            {
                InitEntities[i].Init = init;
                return;
            }
        }
        InitEntities.push_back(EntityTemplate(name, init, desctruct));
    }

    int addEntity(const irr::c8* name = NULL)
    {
        std::cout<<"Added Entity"<<std::endl;
        Entities.push_back(CEntity(LastEntityID++, name));
        for (int i=0;i<InitEntities.size();i++)
        {
            if (InitEntities[i].Name == name)
            {
                InitEntities[i].Init(Entities[Entities.size()-1]);
                Entities[Entities.size()-1].Destructor = InitEntities[i].Destruct;
            }
        }
        return Entities[Entities.size()-1].getEntityID();
    }

    void removeEntity(int i)
    {
        if (Entities.size() > i)
        {
            Entities[i].Destructor(Entities[i]);
            Entities.erase(i);
        }
    }

    void addTimeEvent(int timeMs, TimeEventPointer event)
    {
        TimeEvents.push_back(TimeEvent(Device->getTimer()->getTime()+timeMs, event));
        TimeEvents.sort();
    }

    void Run(void)
    {
        while (Device->run())
        {
            //update entities
            for (int i=0;i<Entities.size();i++)
                Entities[i].UpdateEntity(Device->getTimer()->getTime(), Entities[i]);

            //trigger Events
            while(TimeEvents.size() > 0 && TimeEvents[0].TimeMs < Device->getTimer()->getTime())
            {
                TimeEvents[0].Event();
                TimeEvents.erase(0);
            }


            //Render stuff
            Device->getVideoDriver()->beginScene(true, true, irr::video::SColor(255,0,0,255));

            Device->getSceneManager()->drawAll();

            Device->getGUIEnvironment()->drawAll();

            Device->getVideoDriver()->endScene();
        }

        Device->closeDevice();
    }

    int getTime(void) const
    {
        return Device->getTimer()->getTime();
    }

    irr::IrrlichtDevice* getDevice(void)
    {
        return Device;
    }
protected:
    int LastEntityID;
    irr::core::array<CEntity> Entities;
    class TimeEvent
    {
    public:
        TimeEvent(int timeMs, TimeEventPointer event) : TimeMs(timeMs), Event(event)
        {
        }
        TimeEvent(const TimeEvent& tmp) : TimeMs(tmp.TimeMs), Event(tmp.Event)
        {
        }
        TimeEvent& operator=(const TimeEvent& tmp)
        {
            TimeMs = tmp.TimeMs;
            Event = tmp.Event;
            return *this;
        }
        bool operator<(const TimeEvent& tmp)
        {
            return TimeMs < tmp.TimeMs;
        }
        int TimeMs;
        TimeEventPointer Event;
    };
    class EntityTemplate
    {
    public:
        EntityTemplate(const irr::c8* name, InitPointer init, InitPointer destruct)
        {
            Name = name;
            Init = init;
            Destruct = destruct;
        }
        EntityTemplate(const EntityTemplate& temp)
        {
            Name = temp.Name;
            Init = temp.Init;
            Destruct = temp.Destruct;
        }
        EntityTemplate& operator=(const EntityTemplate& temp)
        {
            Name = temp.Name;
            Init = temp.Init;
            Destruct = temp.Destruct;
            return *this;
        }
        irr::core::stringc Name;
        InitPointer Init;
        InitPointer Destruct;
    };
    irr::core::array<EntityTemplate> InitEntities;
    irr::core::array<TimeEvent> TimeEvents;

    //irrlicht
    irr::IrrlichtDevice* Device;
};

typedef SingeltonTemplate<CGameEngine> GameEngine;

class CPlayerData : public CEntityData
{
public:
    CPlayerData(void)
    {
        Health = 0;
        Node = NULL;
        Cam = NULL;
    }
    ~CPlayerData(void)
    {
        if (Node)
        {
            Node->remove();
            Node->drop();
        }
        if (Cam)
        {
            Cam->remove();
            Cam->drop();
        }
        Node = NULL;
        Cam = NULL;
    }

    irr::scene::ISceneNode* Node;
    irr::scene::ICameraSceneNode* Cam;
    int Health;
};


void UpdatePlayer(int timeMs, CEntity& entity)
{
    std::cout<<"Update Player ["<<entity.getEntityID()<<"] Time: "<<timeMs<<std::endl;
}
void InitPlayer(CEntity& entity)
{
    std::cout<<"Init Player"<<std::endl;
    CPlayerData* data = new CPlayerData;
    entity.setEntityData(data);
    entity.UpdateEntity = &UpdatePlayer;

    //load mesh
    GameEngine engine;
    data->Node = engine->getDevice()->getSceneManager()->addAnimatedMeshSceneNode(engine->getDevice()->getSceneManager()->getMesh("faerie.md2"));
    data->Node->grab();
    data->Cam = engine->getDevice()->getSceneManager()->addCameraSceneNodeFPS();
    data->Cam->grab();
}
void DeInitPlayer(CEntity& entity)
{
    delete entity.getEntityData();
}

void RemovePlayerEvent(void)
{
    GameEngine engine;
    engine->removeEntity(0);
}

void TestEvent(void)
{
    GameEngine engine;
    std::cout<<"Test Event: "<<engine->getTime()<<std::endl;
}

int main(void)
{
    GameEngine engine(new CGameEngine);
    engine->addTimeEvent(10000, &RemovePlayerEvent);
    engine->addTimeEvent(500, &TestEvent);
    engine->RegisterInit("player", &InitPlayer, &DeInitPlayer);
    engine->addEntity("player");
    engine->Run();
    return 0;
}
We're programmers. Programmers are, in their hearts, architects, and the first thing they want to do when they get to a site is to bulldoze the place flat and build something grand. We're not excited by renovation:tinkering,improving,planting flower beds.
FuzzYspo0N
Posts: 914
Joined: Fri Aug 03, 2007 12:43 pm
Location: South Africa
Contact:

Post by FuzzYspo0N »

hey thanks for this sudi, if people do like singelton its a cool reference.
Valmond
Posts: 308
Joined: Thu Apr 12, 2007 3:26 pm

Post by Valmond »

Singletons are extremely useful so this is very nice!

I'll try to work out how you actually use this, you can't just herit this in the class you want to be a singleton right?
sudi
Posts: 1686
Joined: Fri Aug 26, 2005 8:38 pm

Post by sudi »

well its even easier. bc sometimes u can't inherit the class u want to be the singelton. For example the IrrlichtDevice.

Code: Select all

typedef SingeltonTemplate<CGameEngine> GameEngine;
now u init the singelton somewhere in your toplayer

Code: Select all

GameEngine engine(new CGameEngine());
from now on u can just declare

Code: Select all

GameEngine MyEngine;
and use the same objec everywhere. Just keep in mind that the first instance the one u init should not go out of scope.

Just look at the main function and the TestEvent function for an example.
We're programmers. Programmers are, in their hearts, architects, and the first thing they want to do when they get to a site is to bulldoze the place flat and build something grand. We're not excited by renovation:tinkering,improving,planting flower beds.
Post Reply