#include <exception>
#include <iostream>
#include <ostream>
#include <string>

using namespace std;

// ________________ uncaught_exception_count implementation ________________

#if defined(_MSC_VER)
extern "C" char * _getptd();
int uncaught_exception_count()
{
	// MSVC specific. Tested on MSVC2010SP1 x32 and x64.
	return *(static_cast<int*>(static_cast<void*>( _getptd() + (sizeof(void*)==8 ? 0x100 : 0x90) ))); // x32 offset - 0x90 , x64 - 0x100
}
#elif defined(__GNUG__)
extern "C" char * __cxa_get_globals();
int uncaught_exception_count()
{
	return *(static_cast<int*>(static_cast<void*>( __cxa_get_globals() + (sizeof(void*)==8 ? 0x8 : 0x4) ))); // x32 offset - 0x4 , x64 - 0x8
}
#endif

// ________________ uncaught_exception_count test __________________________
struct T800
{
	~T800()
	{
		cout << "uncaught_exception_count=" << uncaught_exception_count() << endl;
	}
};

struct ThrowableDestructor
{
	~ThrowableDestructor()
	{
		throw 0;
	}
};

template<typename FirstScoped, typename SecondScoped=ThrowableDestructor>
struct ExptSwallower
{
	~ExptSwallower()
	{
		try
		{
			FirstScoped a;
			SecondScoped b;
		}catch(...){}
	}
};

void uncaught_exception_count_demo()
{
	T800 a;
	ExptSwallower<T800> b;
	ExptSwallower<ExptSwallower<T800> > c;
	ExptSwallower<ExptSwallower<ExptSwallower<T800> > > d;
	ExptSwallower<ExptSwallower<ExptSwallower<ExptSwallower<T800> > > > e;
}

// ________________ Advanced Scope Guard ___________________________________

// Refer Andrei Alexandrescu talk at:
// http://c...content-available-to-author-only...n.com/Events/Lang-NEXT/Lang-NEXT-2012/Three-Unlikely-Successful-Features-of-D
class DLikeScopeGuard
{
	int exception_enter_state;
public:
	DLikeScopeGuard()
	{
		exception_enter_state=uncaught_exception_count();
	}
	void scope_success()
	{
		cout << "scope_success" << endl;
	}
	void scope_failure()
	{
		cout << "scope_failure" << endl;
	}
	void scope_exit()
	{
		cout << "scope_exit" << endl;
	}
	~DLikeScopeGuard()
	{
		if(exception_enter_state==uncaught_exception_count())
			scope_success();
		else
			scope_failure();
		scope_exit();
	}
};

void scope_guard_demo()
{
	{
		cout << endl << "no exception:" << endl;
		DLikeScopeGuard success;
	}
	try
	{
		cout << endl << "basic throw:" << endl;
		DLikeScopeGuard fail;
		throw 0;
	}catch(...){}
	try
	{
		cout << endl << "fail in previous destructor:" << endl;
		DLikeScopeGuard fail;
		ThrowableDestructor d;
	}catch(...){}
	try
	{
		cout << endl << "fail in next destructor:" << endl;
		ThrowableDestructor d;
		DLikeScopeGuard success;
	}catch(...){}
	try
	{
		cout << endl << "ExptSwallower<DLikeScopeGuard,ThrowableDestructor> during throw:" << endl;
		ExptSwallower<DLikeScopeGuard,ThrowableDestructor> fail;
		throw 0;
	}catch(...){}
	try
	{
		cout << endl << "ExptSwallower<ThrowableDestructor,DLikeScopeGuard> during throw:" << endl;
		ExptSwallower<ThrowableDestructor,DLikeScopeGuard> fail;
		throw 0;
	}catch(...){}
	try
	{
		cout << endl << "ExptSwallower<DLikeScopeGuard,int> during throw:" << endl;
		ExptSwallower<DLikeScopeGuard,int> success;
		throw 0;
	}catch(...){}
}

int main(int argc,char *argv[])
{
	cout << "uncaught_exception_count demo:" << endl << endl;
	uncaught_exception_count_demo();
	cout << std::string(25,'_') << endl;
	cout << "scope_guard demo:" << endl;
	scope_guard_demo();
	return 0;
}

