// Win32Project4.cpp : Definiert den Einstiegspunkt für die Konsolenanwendung.
//

#include "stdafx.h"
#include <Windows.h>
#include <vector>
#include <iostream>
#include <unordered_map>


#define __SEARCH_TYPE__ 1
// 1 = Array
// 2 = Liste
// 3 = dynamic_cast
// 4 = std::unordered_map


class ClassComponent
{
public:
	ClassComponent(int ComponentType)
	{
		m_ComponentType = ComponentType;
		m_pNext = nullptr;
	}

	int GetComponentType(void) const
	{
		return m_ComponentType;
	}

	virtual int Toast(void) = 0;
	virtual void IncValue(void) = 0;
	virtual void DecValue(void) = 0;

	ClassComponent* m_pNext;

private:
	int m_ComponentType;
	int m_Value;
};


template <int ComponentType> class TemplateComponent :
	public ClassComponent
{
public:
	TemplateComponent(void) : ClassComponent(ComponentType)
	{
		m_Value = 0;
	}

	static int GetComponentType(void)
	{
		return ComponentType;
	}

	int Toast(void)
	{
		return ComponentType;
	}

	void IncValue(void)
	{
		++m_Value;
	}

	void DecValue(void)
	{
		++m_Value;
	}

private:
	int m_Value;
};


class ClassComponentArray;


class ClassComponentArrayCaster
{
public:
	template <class T> operator T*(void)
	{
		return m_pArray->FindComponent<T>();
	}

	friend class ClassComponentArray;
private:
	ClassComponentArrayCaster(ClassComponentArray* pArray)
	{
		m_pArray = pArray;
	}

	ClassComponentArray* m_pArray;
};


const int SearchSize = 20;


class ClassComponentArray
{
public:
	ClassComponentArray(void)
	{
		m_ppComponentArray[0] = &m_C0;
		m_ppComponentArray[1] = &m_C1;
		m_ppComponentArray[2] = &m_C2;
		m_ppComponentArray[3] = &m_C3;
		m_ppComponentArray[4] = &m_C4;
		m_ppComponentArray[5] = &m_C5;
		m_ppComponentArray[6] = &m_C6;
		m_ppComponentArray[7] = &m_C7;
		m_ppComponentArray[8] = &m_C8;
		m_ppComponentArray[9] = &m_C9;
		m_ppComponentArray[10] = &m_C10;
		m_ppComponentArray[11] = &m_C11;
		m_ppComponentArray[12] = &m_C12;
		m_ppComponentArray[13] = &m_C13;
		m_ppComponentArray[14] = &m_C14;
		m_ppComponentArray[15] = &m_C15;
		m_ppComponentArray[16] = &m_C16;
		m_ppComponentArray[17] = &m_C17;
		m_ppComponentArray[18] = &m_C18;
		m_ppComponentArray[19] = &m_C19;

		m_Vector.assign(20, nullptr);

		for (int i = 0; i < 20; ++i)
		{
			m_Vector[i] = m_ppComponentArray[i];

			m_HashMap[m_ppComponentArray[i]->GetComponentType()] = m_ppComponentArray[i];

			if (i < 19)
			{
				m_ppComponentArray[i]->m_pNext = m_ppComponentArray[i + 1];
			}
		}
	}

	ClassComponentArrayCaster FindComponent(void)
	{
		return ClassComponentArrayCaster(this);
	}

	void TestInc(void)
	{
		TemplateComponent<0>* p0 = FindComponent();
		TemplateComponent<1>* p1 = FindComponent();
		TemplateComponent<2>* p2 = FindComponent();
		TemplateComponent<3>* p3 = FindComponent();
		TemplateComponent<4>* p4 = FindComponent();
		TemplateComponent<5>* p5 = FindComponent();
		TemplateComponent<6>* p6 = FindComponent();
		TemplateComponent<7>* p7 = FindComponent();
		TemplateComponent<8>* p8 = FindComponent();
		TemplateComponent<9>* p9 = FindComponent();
		TemplateComponent<10>* p10 = FindComponent();
		TemplateComponent<11>* p11 = FindComponent();
		TemplateComponent<12>* p12 = FindComponent();
		TemplateComponent<13>* p13 = FindComponent();
		TemplateComponent<14>* p14 = FindComponent();
		TemplateComponent<15>* p15 = FindComponent();
		TemplateComponent<16>* p16 = FindComponent();
		TemplateComponent<17>* p17 = FindComponent();
		TemplateComponent<18>* p18 = FindComponent();
		TemplateComponent<19>* p19 = FindComponent();

		p0->IncValue();
		p1->IncValue();
		p2->IncValue();
		p3->IncValue();
		p4->IncValue();
		p5->IncValue();
		p6->IncValue();
		p7->IncValue();
		p8->IncValue();
		p9->IncValue();
		p10->IncValue();
		p11->IncValue();
		p12->IncValue();
		p13->IncValue();
		p14->IncValue();
		p15->IncValue();
		p16->IncValue();
		p17->IncValue();
		p18->IncValue();
		p19->IncValue();
	}

	void TestDec(void)
	{
		TemplateComponent<0>* p0 = FindComponent();
		TemplateComponent<1>* p1 = FindComponent();
		TemplateComponent<2>* p2 = FindComponent();
		TemplateComponent<3>* p3 = FindComponent();
		TemplateComponent<4>* p4 = FindComponent();
		TemplateComponent<5>* p5 = FindComponent();
		TemplateComponent<6>* p6 = FindComponent();
		TemplateComponent<7>* p7 = FindComponent();
		TemplateComponent<8>* p8 = FindComponent();
		TemplateComponent<9>* p9 = FindComponent();
		TemplateComponent<10>* p10 = FindComponent();
		TemplateComponent<11>* p11 = FindComponent();
		TemplateComponent<12>* p12 = FindComponent();
		TemplateComponent<13>* p13 = FindComponent();
		TemplateComponent<14>* p14 = FindComponent();
		TemplateComponent<15>* p15 = FindComponent();
		TemplateComponent<16>* p16 = FindComponent();
		TemplateComponent<17>* p17 = FindComponent();
		TemplateComponent<18>* p18 = FindComponent();
		TemplateComponent<19>* p19 = FindComponent();

		p0->DecValue();
		p1->DecValue();
		p2->DecValue();
		p3->DecValue();
		p4->DecValue();
		p5->DecValue();
		p6->DecValue();
		p7->DecValue();
		p8->DecValue();
		p9->DecValue();
		p10->DecValue();
		p11->DecValue();
		p12->DecValue();
		p13->DecValue();
		p14->DecValue();
		p15->DecValue();
		p16->DecValue();
		p17->DecValue();
		p18->DecValue();
		p19->DecValue();
	}

	friend class ClassComponentArrayCaster;
private:
	template <class ComponentClassType> ComponentClassType* FindComponent(void)
	{
#if __SEARCH_TYPE__ == 1

		for (int i = 0; i < 20; ++i)
		{
			if (m_ppComponentArray[i]->GetComponentType() == ComponentClassType::GetComponentType())
			{
				return static_cast<ComponentClassType*>(m_ppComponentArray[i]);
			}
		}

		return nullptr;

#elif __SEARCH_TYPE__ == 2

		ClassComponent* pComponent = m_ppComponentArray[0];
		while (nullptr != pComponent)
		{
			if (pComponent->GetComponentType() == ComponentClassType::GetComponentType())
			{
				return static_cast<ComponentClassType*>(pComponent);
			}

			pComponent = pComponent->m_pNext;
		}

		return nullptr;

#elif __SEARCH_TYPE__ == 3

		for (auto pComponent : m_Vector)
		{
			auto pCheck = dynamic_cast<ComponentClassType*>(pComponent);
			if (pCheck)
			{
				return pCheck;
			}
		}

		return nullptr;

#elif __SEARCH_TYPE__ == 4

		ClassComponent* pComponent = m_HashMap.find(ComponentClassType::GetComponentType())->second;
		return static_cast<ComponentClassType*>(pComponent);

#endif
	}

	ClassComponent* m_ppComponentArray[20];
	std::vector<ClassComponent*> m_Vector;
	std::unordered_map<int, ClassComponent*> m_HashMap;

	TemplateComponent<0> m_C0;
	TemplateComponent<1> m_C1;
	TemplateComponent<2> m_C2;
	TemplateComponent<3> m_C3;
	TemplateComponent<4> m_C4;
	TemplateComponent<5> m_C5;
	TemplateComponent<6> m_C6;
	TemplateComponent<7> m_C7;
	TemplateComponent<8> m_C8;
	TemplateComponent<9> m_C9;
	TemplateComponent<10> m_C10;
	TemplateComponent<11> m_C11;
	TemplateComponent<12> m_C12;
	TemplateComponent<13> m_C13;
	TemplateComponent<14> m_C14;
	TemplateComponent<15> m_C15;
	TemplateComponent<16> m_C16;
	TemplateComponent<17> m_C17;
	TemplateComponent<18> m_C18;
	TemplateComponent<19> m_C19;
};


int main()
{
	ClassComponentArray CA;

	LARGE_INTEGER PC1;
	QueryPerformanceCounter(&PC1);

	DWORD TC1 = GetTickCount();

	for (int i = 0; i < 10000000; ++i)
	{
		CA.TestInc();
	}

	for (int i = 0; i < 10000000; ++i)
	{
		CA.TestDec();
	}

	LARGE_INTEGER PC2;
	QueryPerformanceCounter(&PC2);

	DWORD TC2 = GetTickCount();

	LARGE_INTEGER D;
	D.QuadPart = PC2.QuadPart - PC1.QuadPart;

	std::cout << D.QuadPart << std::endl;
	std::cout << TC2 - TC1 << std::endl;

	int i;
	std::cin >> i;
}

