#include <iostream>
// component regitry
#include <unordered_map>
#include <functional>
#include <memory>
#define DEBUG_COMPONENT_CREATION(X)
#include <cstdint> // for std::uint64_t
#include <random>
template <typename T>
class CGUID_t
{
public:
typedef T TGuidValueType;
constexpr static T INVALID_GUID = -1;
CGUID_t() : value(Generate()) {}
//CGUID(T value_) : value(value_) {}
bool IsValid() const { return value != INVALID_GUID; }
T GetValue() const { return value; }
static T Generate()
{
std::random_device rd; //Will be used to obtain a seed for the random number engine
std::mt19937 generator(rd()); //Standard mersenne_twister_engine seeded with rd()
std::uniform_int_distribution<T> distribution(static_cast<T>(1), static_cast<T>(-1));
return distribution(generator);
}
private:
T value;
};
typedef CGUID_t<std::uint64_t> CGUID;
struct IComponent
{
IComponent()
{
DEBUG_COMPONENT_CREATION(uid);
}
virtual ~IComponent() {};
virtual void Update() = 0;
virtual void Init() = 0;
virtual void Shutdown() = 0;
virtual void RegisterForUpdate() = 0;
CGUID GetGUID() const { return guid; }
private:
CGUID guid;
};
#undef DEBUG_COMPONENT_CREATION
struct STEST
{
STEST()
{
std::cout << "[Info] STEST" << std::endl;
}
~STEST()
{
std::cout << "[Info] ~STEST" << std::endl;
}
};
template <class PRODUCT_PTR = IComponent>
class CComponentFactory
{
public:
CComponentFactory()
{
std::cout << "[Info] CComponentFactory" << std::endl;
}
static void Register(const std::string id, std::function<PRODUCT_PTR*()> funCreate)
{
// uses pair's converting move constructor
// auto const res = GetMap().emplace(std::make_pair(id, pComponent));
#if 1
auto search = GetMap().find(id);
if(search == GetMap().end()) {
std::cout << "[Info] Registered Component " << id << std::endl;
GetMap()[id] = funCreate;
}
else {
std::cout << "[Warning] CComponentFactory::Register: Component " << id << " already registered!!" << std::endl;
}
#else
// auto const res = std::pair<std::string,bool>("a",false); //GetMap().emplace(id, pComponent);
auto aa = std::pair<std::string, const PRODUCT_PTR*>(id, pComponent);
auto const res = GetMap().emplace(aa);
// auto const res = GetMap().emplace(id, pComponent);
if (!res.second)
{
// insertion failed
std::cout << "[Warning] CComponentFactory::Register: Component " << id << " already registered!!" << std::endl;
}
#endif
}
static std::unique_ptr<PRODUCT_PTR> Construct(const std::string& id)
{
auto search = GetMap().find(id);
if(search != GetMap().end()) {
std::cout << "[Info] Constructed Component " << search->first << std::endl;
return std::unique_ptr<PRODUCT_PTR>(search->second());
}
else {
std::cout << "[Warning] Failed to Construct Component " << id << std::endl;
return std::unique_ptr<PRODUCT_PTR>(nullptr);
}
}
private:
using TComponentFactoryMap = std::unordered_map<std::string, std::function<PRODUCT_PTR*()>>;
static TComponentFactoryMap& GetMap() {
static TComponentFactoryMap s_map; // NOTE: GETS CONSTRUCTED TWICE!!! once befor main() and once in main()
static STEST s_stest;
static int i = 0;
std::cout << "[Info] i: " << i++ << " addr: " << &i << std::endl;
return s_map;
}
};
class RenderComponent : public IComponent
{
public:
RenderComponent()
{
std::cout << "Creating componenet with GUID: " << GetGUID().GetValue() << std::endl;
}
virtual ~RenderComponent() override
{
std::cout << "Destroying componenet with GUID: " << GetGUID().GetValue() << std::endl;
}
virtual void Init() override {};
virtual void Update() override {};
virtual void Shutdown() override {};
virtual void RegisterForUpdate() override {};
};
template <class TEST_TYPE_PTR>
class CRegister_RenderComponent
{
public:
CRegister_RenderComponent()
{
CComponentFactory<TEST_TYPE_PTR>::Register(std::string("RenderComponent"), []() { return new TEST_TYPE_PTR;});
}
};
static CRegister_RenderComponent<RenderComponent> s_CRegister_RenderComponent;
static CRegister_RenderComponent<RenderComponent> s_CRegister_RenderComponent2;
bool test_icomponent()
{
RenderComponent rc;
bool bValid = rc.GetGUID().IsValid();
std::cout << "componenet with GUID: " << rc.GetGUID().GetValue() << " is " << (bValid ? "Valid" : "Invalid") << std::endl;
if (auto uPtr = CComponentFactory<IComponent>::Construct("RenderComponent")) {
std::cout << "Construted component " << (uPtr->GetGUID().GetValue()) << std::endl;
}
return true;
}
int main()
{
test_icomponent();
return 0;
}