#include <memory> //Smart pointers
#include <string> //Strings
#include <iostream> //Ausgabe



void testCaption(std::string caption){
	std::cout << "-----------------------------------" << std::endl;
	std::cout << "Teste " << caption << std::endl;
}


//--------------------------------------------------------------
// Extended for loop:
//--------------------------------------------------------------

/**
 * Die "neue" for Schleife funktioniert
 * mit jeder Klasse die begin() und end()
 * bereit stellt.
 *
 * Beide Methoden müssen dabei einen "Pointer-artigen" Typen
 * zurückliefern, also entweder einen Pointer oder eine
 * Klasse die die operator *, !=, und ++ überläd.
 *
 */


//Diese Klasse erlaubt die Benutzung der for Schleife
struct X{

	int x [100];
	X(){ for (int i = 0 ; i < 100 ; i++) x[i] = i*2; }

	int* begin(){
		return x;
	}

	int* end(){
		return x + 100;
	}

};

void testForLoop(){
	testCaption("for loop");
	X x;
	//Neue for Schleife:
	for ( int i : x ){
		std::cout << i << std::endl;
	}

	//Äquivalent zu folgendem code:
	for ( int* cur = x.begin(), *end = x.end() ; cur != end ; cur++ ){
		int i = *cur;
		std::cout << i << std::endl;
	}
}



//--------------------------------------------------------------
// Smart pointers
//--------------------------------------------------------------

struct Y{
	Y(){ std::cout << "Y@" << this << " wurde erstellt" << std::endl; }
	~Y(){ std::cout << "Y@" << this << " wurde zerstört" << std::endl; }
};

void testSmartptr(){
	testCaption("smart pointer");
	{
		//Locale Variable y wird zerstört sobald sie out-of-scope geht
		Y y;
	}
	std::cout << "Ende Block 1" << std::endl;
	{
		Y* y = new Y(); //Dieses Y wird nicht zerstört! Memory leak!
	}
	std::cout << "Ende Block 2 " << std::endl;
	{
		//Obwohl ein Y mit "new" erstellt wurde löscht der unique_ptr
		//das Y sobald er selbst gelöscht wird.
		//Da der unique_ptr hier lokal ist, wird er und somit auch das
		//Y gelöscht sobald die Variable ptr out-of-scope geht
		std::unique_ptr<Y> ptr { new Y() };
		//Dasselbe gilt für shared_ptr wobei hier mehrere Kopien des
		//Pointers erstellt werden können
		std::shared_ptr<Y> ptr2 { new Y() };

	}
	std::cout << "Ende Block 3 " << std::endl;
}


//--------------------------------------------------------------
// Virtuelle Funktionen und Memory Layout
//--------------------------------------------------------------
struct A{
	int i;
};

//Klasse B ist wie Klasse A, hat aber eine virtuelle Funktion.
//Somit muss der VTable Pointer in B gespeichert werden wodurch
//Objekte vom Typ B mehr Platz brauchen
struct B{
	int i;
	virtual void foo(){}
};

void testVirtual(){
	testCaption("virtual function space usage");

	std::cout << "Klasse A braucht " << sizeof(A) << " bytes" << std::endl;
	std::cout << "Klasse B braucht " << sizeof(B) << " bytes" << std::endl;
}

//template<typename T>
//class SmartPtr{
//	T* ptr;
//
//	T& operator*(){
//		return *ptr;
//	}
//
//};
//
//
//struct Functor{
//
//	void operator()(std::vector<int>* v, int start, int end){
//		std::sort(v->begin()+start,v->begin()+end);
//	}
//};
//
//struct FuncUser{
//
//	template<typename T>
//	FuncUser(T&& t){
//		t();
//	}
//
//};
//
//void saySomething(){
//	for(int i = 0; i < 10000 ; i++){
//		std::cout << "Foo" << i << std::endl;
//	}
//}
//
//void foo(){
//	std::thread t(saySomething);
//	t.detach();
//}

//Main Funktion testet alle Konzepte
int main(){
	testForLoop();
	testSmartptr();
	testVirtual();
}
