code:
//
// This generator creates a header file that implements automatic
// wrapper functions for the generic calling convention.
//
// Originally implemented by George Yohng from 4Front Technologies in 2009-03-11
// Modifications by Pierre Fortin in order to add constructor wrapper generation
//
// A completely new implementation of automatic wrapper functions was
// implemented by SiCrane at GameDev.net in 2011-12-18. The generator was
// adapted from Python to C++ by Andreas.
//
// ref: http://www.gamedev.net/topic/617111-more-angelscript-binding-wrappers/
//

#include <stdio.h>
#include <string>

// Generate templates for up to this number of function parameters
const int max_args = 4;

using namespace std;

void PrintTemplate(const char *base, const char *typeNameList, const char *retType, const char *objType, const char *isConst, const char *newExpr, const char *objExpr, const char *argList1, const char *argList2, const char *wrapName);
void PrintConstructor(const char *comma, const char *typeNameList, const char *typeList, const char *argList);

int main()
{
	printf("#ifndef AS_GEN_WRAPPER_H\n"
	"#define AS_GEN_WRAPPER_H\n"
	"\n"
	"#ifndef ANGELSCRIPT_H\n"
	"// Avoid having to inform include path if header is already include before\n"
	"#include <angelscript.h>\n"
	"#endif\n"
	"#include <new>\n"
	"\n"
	"namespace gw {\n"
	"\n"
	"template <typename T> class Proxy {\n"
	"	public:\n"
	"		T value;\n"
	"		Proxy(T value) : value(value) {}\n"
	"		static T cast(void * ptr) {\n"
	"			return reinterpret_cast<Proxy<T> *>(&ptr)->value;\n"
	"		}\n"
	"	private:\n"
	"		Proxy(const Proxy &);\n"
	"		Proxy & operator=(const Proxy &);\n"
	"};\n"
	"\n"
	"template <typename T> struct Wrapper {};\n"
	"template <typename T> struct WrapperGlobal {};\n"
	"template <typename T> struct ObjFirst {};\n"
	"template <typename T> struct ObjLast {};\n"
	"template <typename T> struct Constructor {};\n"
	"\n"
	"template <typename T>\n"
	"void destroy(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {\n"
	"	static_cast<T *>(gen->GetObject())->~T();\n"
	"}\n");

	string typename_list = "typename A0";
	string type_list     = "A0";
	string arg_list      = "\n				static_cast<Proxy <A0> *>(gen->GetAddressOfArg(0))->value";
	string new_exp       = "new (gen->GetAddressOfReturnLocation()) Proxy<R>";
	string obj_exp       = "static_cast<T *>(gen->GetObject())->*";
	string obj_arg_exp   = "\n				Proxy<T>::cast(gen->GetObject())";
	string obj_g_exp     = "static_cast<T *>(gen->GetAuxiliary())->*";

	PrintTemplate("",                       "", "void", "",    "",       "",              "",              "void", "", "Wrapper");
	PrintTemplate("typename R",             "", "R",    "",    "",       new_exp.c_str(), "",              "void", "", "Wrapper");

	PrintTemplate("typename T",             "", "void", "T::", "",       "",              obj_exp.c_str(), "void", "", "Wrapper");
	PrintTemplate("typename T, typename R", "", "R",    "T::", "",       new_exp.c_str(), obj_exp.c_str(), "void", "", "Wrapper");
	PrintTemplate("typename T",             "", "void", "T::", " const", "",              obj_exp.c_str(), "void", "", "Wrapper");
	PrintTemplate("typename T, typename R", "", "R",    "T::", " const", new_exp.c_str(), obj_exp.c_str(), "void", "", "Wrapper");

	PrintTemplate("typename T",             "", "void", "T::", "",       "",              obj_g_exp.c_str(), "void", "", "WrapperGlobal");
	PrintTemplate("typename T, typename R", "", "R",    "T::", "",       new_exp.c_str(), obj_g_exp.c_str(), "void", "", "WrapperGlobal");
	PrintTemplate("typename T",             "", "void", "T::", " const", "",              obj_g_exp.c_str(), "void", "", "WrapperGlobal");
	PrintTemplate("typename T, typename R", "", "R",    "T::", " const", new_exp.c_str(), obj_g_exp.c_str(), "void", "", "WrapperGlobal");

	PrintTemplate("typename T",             "", "void", "",    "",       "",              "",      "T",    obj_arg_exp.c_str(), "ObjFirst");
	PrintTemplate("typename T, typename R", "", "R",    "",    "",       new_exp.c_str(), "",      "T",    obj_arg_exp.c_str(), "ObjFirst");
	PrintTemplate("typename T",             "", "void", "",    "",       "",              "",      "T",    obj_arg_exp.c_str(), "ObjLast");
	PrintTemplate("typename T, typename R", "", "R",    "",    "",       new_exp.c_str(), "",      "T",    obj_arg_exp.c_str(), "ObjLast");

	PrintConstructor("", "", "", "");

	for( int i = 0; i < max_args; i++ )
	{
		PrintTemplate("",                         typename_list.c_str(), "void", "",    "",       "",              "",              type_list.c_str(), arg_list.c_str(), "Wrapper");
		PrintTemplate("typename R, ",             typename_list.c_str(), "R",    "",    "",       new_exp.c_str(), "",              type_list.c_str(), arg_list.c_str(), "Wrapper");

		PrintTemplate("typename T, ",             typename_list.c_str(), "void", "T::", "",       "",              obj_exp.c_str(), type_list.c_str(), arg_list.c_str(), "Wrapper");
		PrintTemplate("typename T, typename R, ", typename_list.c_str(), "R",    "T::", "",       new_exp.c_str(), obj_exp.c_str(), type_list.c_str(), arg_list.c_str(), "Wrapper");
		PrintTemplate("typename T, ",             typename_list.c_str(), "void", "T::", " const", "",              obj_exp.c_str(), type_list.c_str(), arg_list.c_str(), "Wrapper");
		PrintTemplate("typename T, typename R, ", typename_list.c_str(), "R",    "T::", " const", new_exp.c_str(), obj_exp.c_str(), type_list.c_str(), arg_list.c_str(), "Wrapper");

		PrintTemplate("typename T, ",             typename_list.c_str(), "void", "T::", "",       "",              obj_g_exp.c_str(), type_list.c_str(), arg_list.c_str(), "WrapperGlobal");
		PrintTemplate("typename T, typename R, ", typename_list.c_str(), "R",    "T::", "",       new_exp.c_str(), obj_g_exp.c_str(), type_list.c_str(), arg_list.c_str(), "WrapperGlobal");
		PrintTemplate("typename T, ",             typename_list.c_str(), "void", "T::", " const", "",              obj_g_exp.c_str(), type_list.c_str(), arg_list.c_str(), "WrapperGlobal");
		PrintTemplate("typename T, typename R, ", typename_list.c_str(), "R",    "T::", " const", new_exp.c_str(), obj_g_exp.c_str(), type_list.c_str(), arg_list.c_str(), "WrapperGlobal");

		PrintTemplate("typename T, ",             typename_list.c_str(), "void", "", "", "",              "", ("T, " + type_list).c_str(), (obj_arg_exp + "," + arg_list).c_str(), "ObjFirst");
		PrintTemplate("typename T, typename R, ", typename_list.c_str(), "R",    "", "", new_exp.c_str(), "", ("T, " + type_list).c_str(), (obj_arg_exp + "," + arg_list).c_str(), "ObjFirst");
		PrintTemplate("typename T, ",             typename_list.c_str(), "void", "", "", "",              "", (type_list + ", T").c_str(), (arg_list + "," + obj_arg_exp).c_str(), "ObjLast");
		PrintTemplate("typename T, typename R, ", typename_list.c_str(), "R",    "", "", new_exp.c_str(), "", (type_list + ", T").c_str(), (arg_list + "," + obj_arg_exp).c_str(), "ObjLast");

		PrintConstructor(", ", typename_list.c_str(), type_list.c_str(), arg_list.c_str());

		char buf[5];
		sprintf(buf, "%d", i + 1);
		typename_list += ", typename A" + string(buf);
		type_list     += ", A" + string(buf);
		arg_list      += ",\n				static_cast<Proxy <A" + string(buf) + "> *>(gen->GetAddressOfArg(" + string(buf) + "))->value";
	}

	printf("template <typename T>\n"
	"struct Id {\n"
	"	template <T fn_ptr> AS_NAMESPACE_QUALIFIER asSFuncPtr  f(void) { return AS_NAMESPACE_QUALIFIER asFUNCTION(&Wrapper<T>::template f<fn_ptr>); }\n"
	"	template <T fn_ptr> AS_NAMESPACE_QUALIFIER asSFuncPtr fg(void) { return AS_NAMESPACE_QUALIFIER asFUNCTION(&WrapperGlobal<T>::template f<fn_ptr>); }\n"
	"	template <T fn_ptr> AS_NAMESPACE_QUALIFIER asSFuncPtr of(void) { return AS_NAMESPACE_QUALIFIER asFUNCTION(&ObjFirst<T>::template f<fn_ptr>); }\n"
	"	template <T fn_ptr> AS_NAMESPACE_QUALIFIER asSFuncPtr ol(void) { return AS_NAMESPACE_QUALIFIER asFUNCTION(&ObjLast<T>::template f<fn_ptr>); }\n"
	"};\n"
	"\n"
	"template <typename T>\n"
	"Id<T> id(T fn_ptr) { return Id<T>(); }\n"
	"\n"
	"// On GNUC it is necessary to use the template keyword as disambiguator.\n"
	"// MSVC seems to accept both with or without the template keyword.\n"
	"#if defined(__GNUC__)\n"
	"	#define TMPL template\n"
	"#else\n"
	"	#define TMPL\n"
	"#endif\n"
	"\n"
	"#define WRAP_FN(name)             (::gw::id(name).TMPL f< name >())\n"
	"#define WRAP_MFN(ClassType, name) (::gw::id(&ClassType::name).TMPL f< &ClassType::name >())\n"
	"#define WRAP_MFN_GLOBAL(ClassType, name) (::gw::id(&ClassType::name).TMPL fg< &ClassType::name >())\n"
	"#define WRAP_OBJ_FIRST(name)      (::gw::id(name).TMPL of< name >())\n"
	"#define WRAP_OBJ_LAST(name)       (::gw::id(name).TMPL ol< name >())\n"
	"\n"
	"#define WRAP_FN_PR(name, Parameters, ReturnType)             asFUNCTION((::gw::Wrapper<ReturnType (*)Parameters>::TMPL f< name >))\n"
	"#if defined(__clang__)\n"
	" // Clang doesn't like the use of AS_METHOD_AMBIGUITY_CAST in the inner template\n"
	" #define WRAP_MFN_PR(ClassType, name, Parameters, ReturnType) asFUNCTION((::gw::Wrapper<ReturnType (ClassType::*)Parameters>::TMPL f< &ClassType::name >))\n"
	" #define WRAP_MFN_GLOBAL_PR(ClassType, name, Parameters, ReturnType) asFUNCTION((::gw::WrapperGlobal<ReturnType (ClassType::*)Parameters>::TMPL f< &ClassType::name >))\n"
	"#else\n"
	" #define WRAP_MFN_PR(ClassType, name, Parameters, ReturnType) asFUNCTION((::gw::Wrapper<ReturnType (ClassType::*)Parameters>::TMPL f< AS_METHOD_AMBIGUITY_CAST(ReturnType (ClassType::*)Parameters)(&ClassType::name) >))\n"
	" #define WRAP_MFN_GLOBAL_PR(ClassType, name, Parameters, ReturnType) asFUNCTION((::gw::WrapperGlobal<ReturnType (ClassType::*)Parameters>::TMPL f< AS_METHOD_AMBIGUITY_CAST(ReturnType (ClassType::*)Parameters)(&ClassType::name) >))\n"
	"#endif\n"
	"#define WRAP_OBJ_FIRST_PR(name, Parameters, ReturnType)      asFUNCTION((::gw::ObjFirst<ReturnType (*)Parameters>::TMPL f< name >))\n"
	"#define WRAP_OBJ_LAST_PR(name, Parameters, ReturnType)       asFUNCTION((::gw::ObjLast<ReturnType (*)Parameters>::TMPL f< name >))\n"
	"\n"
	"#define WRAP_CON(ClassType, Parameters) asFUNCTION((::gw::Constructor<ClassType Parameters>::f))\n"
	"#define WRAP_DES(ClassType)             asFUNCTION((::gw::destroy<ClassType>))\n"
	"\n"
	"} // end namespace gw\n"
	"\n"
	"#endif\n");

	return 0;
}

void PrintTemplate(const char *base, const char *typeNameList, const char *retType, const char *objType, const char *isConst, const char *newExpr, const char *objExpr, const char *argList1, const char *argList2, const char *wrapName)
{
	printf("template <%s%s>\n", base, typeNameList);
	printf("struct %s<%s (%s*)(%s)%s> {\n", wrapName, retType, objType, argList1, isConst);
	printf("	template <%s (%s*fp)(%s)%s>\n", retType, objType, argList1, isConst);
	printf("	static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {\n");
	printf("		%s((%sfp)(%s));\n", newExpr, objExpr, argList2);
	printf("	}\n");
	printf("};\n");
}

void PrintConstructor(const char *comma, const char *typeNameList, const char *typeList, const char *argList)
{
	printf("template <typename T%s%s>\n", comma, typeNameList);
	printf("struct Constructor <T (%s)> {\n", typeList);
	printf("	static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {\n");
	printf("		new (gen->GetObject()) T(%s);\n", argList);
	printf("	}\n");
	printf("};\n");
}


code:
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
	ProjectType="Visual C++"
	Version="9,00"
	Name="generator"
	ProjectGUID="{086A2F1A-01B1-4EB3-A8FA-0926FF10E953}"
	TargetFrameworkVersion="0"
	>
	<Platforms>
		<Platform
			Name="Win32"
		/>
	</Platforms>
	<ToolFiles>
	</ToolFiles>
	<Configurations>
		<Configuration
			Name="Debug|Win32"
			OutputDirectory=".\Debug"
			IntermediateDirectory=".\Debug"
			ConfigurationType="1"
			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"
			UseOfMFC="0"
			ATLMinimizesCRunTimeLibraryUsage="false"
			CharacterSet="2"
			>
			<Tool
				Name="VCPreBuildEventTool"
			/>
			<Tool
				Name="VCCustomBuildTool"
			/>
			<Tool
				Name="VCXMLDataGeneratorTool"
			/>
			<Tool
				Name="VCWebServiceProxyGeneratorTool"
			/>
			<Tool
				Name="VCMIDLTool"
				TypeLibraryName=".\Debug/generator.tlb"
				HeaderFileName=""
			/>
			<Tool
				Name="VCCLCompilerTool"
				Optimization="0"
				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
				MinimalRebuild="true"
				BasicRuntimeChecks="3"
				RuntimeLibrary="1"
				PrecompiledHeaderFile=".\Debug/generator.pch"
				AssemblerListingLocation=".\Debug/"
				ObjectFile=".\Debug/"
				ProgramDataBaseFileName=".\Debug/"
				WarningLevel="3"
				SuppressStartupBanner="true"
				DebugInformationFormat="4"
			/>
			<Tool
				Name="VCManagedResourceCompilerTool"
			/>
			<Tool
				Name="VCResourceCompilerTool"
				PreprocessorDefinitions="_DEBUG"
				Culture="1033"
			/>
			<Tool
				Name="VCPreLinkEventTool"
			/>
			<Tool
				Name="VCLinkerTool"
				OutputFile=".\Debug/generator.exe"
				LinkIncremental="2"
				SuppressStartupBanner="true"
				GenerateDebugInformation="true"
				ProgramDatabaseFile=".\Debug/generator.pdb"
				SubSystem="1"
				RandomizedBaseAddress="1"
				DataExecutionPrevention="0"
				TargetMachine="1"
			/>
			<Tool
				Name="VCALinkTool"
			/>
			<Tool
				Name="VCManifestTool"
			/>
			<Tool
				Name="VCXDCMakeTool"
			/>
			<Tool
				Name="VCBscMakeTool"
				SuppressStartupBanner="true"
				OutputFile=".\Debug/generator.bsc"
			/>
			<Tool
				Name="VCFxCopTool"
			/>
			<Tool
				Name="VCAppVerifierTool"
			/>
			<Tool
				Name="VCPostBuildEventTool"
			/>
		</Configuration>
		<Configuration
			Name="Release|Win32"
			OutputDirectory=".\Release"
			IntermediateDirectory=".\Release"
			ConfigurationType="1"
			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"
			UseOfMFC="0"
			ATLMinimizesCRunTimeLibraryUsage="false"
			CharacterSet="2"
			>
			<Tool
				Name="VCPreBuildEventTool"
			/>
			<Tool
				Name="VCCustomBuildTool"
			/>
			<Tool
				Name="VCXMLDataGeneratorTool"
			/>
			<Tool
				Name="VCWebServiceProxyGeneratorTool"
			/>
			<Tool
				Name="VCMIDLTool"
				TypeLibraryName=".\Release/generator.tlb"
				HeaderFileName=""
			/>
			<Tool
				Name="VCCLCompilerTool"
				Optimization="2"
				InlineFunctionExpansion="1"
				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
				StringPooling="true"
				RuntimeLibrary="0"
				EnableFunctionLevelLinking="true"
				PrecompiledHeaderFile=".\Release/generator.pch"
				AssemblerListingLocation=".\Release/"
				ObjectFile=".\Release/"
				ProgramDataBaseFileName=".\Release/"
				WarningLevel="3"
				SuppressStartupBanner="true"
			/>
			<Tool
				Name="VCManagedResourceCompilerTool"
			/>
			<Tool
				Name="VCResourceCompilerTool"
				PreprocessorDefinitions="NDEBUG"
				Culture="1033"
			/>
			<Tool
				Name="VCPreLinkEventTool"
			/>
			<Tool
				Name="VCLinkerTool"
				OutputFile=".\Release/generator.exe"
				LinkIncremental="1"
				SuppressStartupBanner="true"
				ProgramDatabaseFile=".\Release/generator.pdb"
				SubSystem="1"
				RandomizedBaseAddress="1"
				DataExecutionPrevention="0"
				TargetMachine="1"
			/>
			<Tool
				Name="VCALinkTool"
			/>
			<Tool
				Name="VCManifestTool"
			/>
			<Tool
				Name="VCXDCMakeTool"
			/>
			<Tool
				Name="VCBscMakeTool"
				SuppressStartupBanner="true"
				OutputFile=".\Release/generator.bsc"
			/>
			<Tool
				Name="VCFxCopTool"
			/>
			<Tool
				Name="VCAppVerifierTool"
			/>
			<Tool
				Name="VCPostBuildEventTool"
			/>
		</Configuration>
	</Configurations>
	<References>
	</References>
	<Files>
		<Filter
			Name="Source Files"
			Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
			>
			<File
				RelativePath="generateheader.cpp"
				>
				<FileConfiguration
					Name="Debug|Win32"
					>
					<Tool
						Name="VCCLCompilerTool"
						PreprocessorDefinitions=""
					/>
				</FileConfiguration>
				<FileConfiguration
					Name="Release|Win32"
					>
					<Tool
						Name="VCCLCompilerTool"
						PreprocessorDefinitions=""
					/>
				</FileConfiguration>
			</File>
		</Filter>
		<Filter
			Name="Header Files"
			Filter="h;hpp;hxx;hm;inl"
			>
		</Filter>
		<Filter
			Name="Resource Files"
			Filter="ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
			>
		</Filter>
	</Files>
	<Globals>
	</Globals>
</VisualStudioProject>

repo_name: Antidote/openrpgeditor

license: mit


code:
#include <assert.h>
#include <string>

#include "contextmgr.h"

using namespace std;

// TODO: Should have a pool of free asIScriptContext so that new contexts
//       won't be allocated every time. The application must not keep
//       its own references, instead it must tell the context manager
//       that it is using the context. Otherwise the context manager may
//       think it can reuse the context too early.

// TODO: Need to have a callback for when scripts finishes, so that the
//       application can receive return values.

BEGIN_AS_NAMESPACE

// The id for the context manager user data.
// The add-ons have reserved the numbers 1000
// through 1999 for this purpose, so we should be fine.
const asPWORD CONTEXT_MGR = 1002;

struct SContextInfo
{
	asUINT                    sleepUntil;
	vector<asIScriptContext*> coRoutines;
	asUINT                    currentCoRoutine;
	asIScriptContext *        keepCtxAfterExecution;
};

static void ScriptSleep(asUINT milliSeconds)
{
	// Get a pointer to the context that is currently being executed
	asIScriptContext *ctx = asGetActiveContext();
	if( ctx )
	{
		// Get the context manager from the user data
		CContextMgr *ctxMgr = reinterpret_cast<CContextMgr*>(ctx->GetUserData(CONTEXT_MGR));
		if( ctxMgr )
		{
			// Suspend its execution. The VM will continue until the current
			// statement is finished and then return from the Execute() method
			ctx->Suspend();

			// Tell the context manager when the context is to continue execution
			ctxMgr->SetSleeping(ctx, milliSeconds);
		}
	}
}

static void ScriptYield()
{
	// Get a pointer to the context that is currently being executed
	asIScriptContext *ctx = asGetActiveContext();
	if( ctx )
	{
		// Get the context manager from the user data
		CContextMgr *ctxMgr = reinterpret_cast<CContextMgr*>(ctx->GetUserData(CONTEXT_MGR));
		if( ctxMgr )
		{
			// Let the context manager know that it should run the next co-routine
			ctxMgr->NextCoRoutine();

			// The current context must be suspended so that VM will return from
			// the Execute() method where the context manager will continue.
			ctx->Suspend();
		}
	}
}

void ScriptCreateCoRoutine(asIScriptFunction *func, CScriptDictionary *arg)
{
	if( func == 0 )
		return;

	asIScriptContext *ctx = asGetActiveContext();
	if( ctx )
	{
		// Get the context manager from the user data
		CContextMgr *ctxMgr = reinterpret_cast<CContextMgr*>(ctx->GetUserData(CONTEXT_MGR));
		if( ctxMgr )
		{
			// Create a new context for the co-routine
			asIScriptContext *coctx = ctxMgr->AddContextForCoRoutine(ctx, func);

			// Pass the argument to the context
			coctx->SetArgObject(0, arg);

			// The context manager will call Execute() on the context when it is time
		}
	}
}

#ifdef AS_MAX_PORTABILITY
void ScriptYield_generic(asIScriptGeneric *)
{
	ScriptYield();
}

void ScriptCreateCoRoutine_generic(asIScriptGeneric *gen)
{
	asIScriptFunction *func = reinterpret_cast<asIScriptFunction*>(gen->GetArgAddress(0));
	CScriptDictionary *dict = reinterpret_cast<CScriptDictionary*>(gen->GetArgAddress(1));
	ScriptCreateCoRoutine(func, dict);
}
#endif

CContextMgr::CContextMgr()
{
	m_getTimeFunc   = 0;
	m_currentThread = 0;

	m_numExecutions         = 0;
	m_numGCObjectsCreated   = 0;
	m_numGCObjectsDestroyed = 0;
}

CContextMgr::~CContextMgr()
{
	asUINT n;

	// Free the memory
	for( n = 0; n < m_threads.size(); n++ )
	{
		if( m_threads[n] )
		{
			for( asUINT c = 0; c < m_threads[n]->coRoutines.size(); c++ )
			{
				asIScriptContext *ctx = m_threads[n]->coRoutines[c];
				if( ctx )
				{
					// Return the context to the engine (and possible context pool configured in it)
					ctx->GetEngine()->ReturnContext(ctx);
				}
			}

			delete m_threads[n];
		}
	}

	for( n = 0; n < m_freeThreads.size(); n++ )
	{
		if( m_freeThreads[n] )
		{
			assert( m_freeThreads[n]->coRoutines.size() == 0 );

			delete m_freeThreads[n];
		}
	}
}

int CContextMgr::ExecuteScripts()
{
	// TODO: Should have an optional time out for this function. If not all scripts executed before the
	//       time out, the next time the function is called the loop should continue
	//       where it left off.

	// TODO: There should be a time out per thread as well. If a thread executes for too
	//       long, it should be aborted. A group of co-routines count as a single thread.

	// Check if the system time is higher than the time set for the contexts
	asUINT time = m_getTimeFunc ? m_getTimeFunc() : asUINT(-1);
	for( m_currentThread = 0; m_currentThread < m_threads.size(); m_currentThread++ )
	{
		SContextInfo *thread = m_threads[m_currentThread];
		if( thread->sleepUntil < time )
		{
			int currentCoRoutine = thread->currentCoRoutine;

			// Gather some statistics from the GC
			asIScriptEngine *engine = thread->coRoutines[currentCoRoutine]->GetEngine();
			asUINT gcSize1, gcSize2, gcSize3;
			engine->GetGCStatistics(&gcSize1);

			// Execute the script for this thread and co-routine
			int r = thread->coRoutines[currentCoRoutine]->Execute();

			// Determine how many new objects were created in the GC
			engine->GetGCStatistics(&gcSize2);
			m_numGCObjectsCreated += gcSize2 - gcSize1;
			m_numExecutions++;

			if( r != asEXECUTION_SUSPENDED )
			{
				// The context has terminated execution (for one reason or other)
				// Unless the application has requested to keep the context we'll return it to the pool now
				if( thread->keepCtxAfterExecution != thread->coRoutines[currentCoRoutine] )
					engine->ReturnContext(thread->coRoutines[currentCoRoutine]);
				thread->coRoutines[currentCoRoutine] = 0;

				thread->coRoutines.erase(thread->coRoutines.begin() + thread->currentCoRoutine);
				if( thread->currentCoRoutine >= thread->coRoutines.size() )
					thread->currentCoRoutine = 0;

				// If this was the last co-routine terminate the thread
				if( thread->coRoutines.size() == 0 )
				{
					m_freeThreads.push_back(thread);
					m_threads.erase(m_threads.begin() + m_currentThread);
					m_currentThread--;
				}
			}

			// Destroy all known garbage if any new objects were created
			if( gcSize2 > gcSize1 )
			{
				engine->GarbageCollect(asGC_FULL_CYCLE | asGC_DESTROY_GARBAGE);

				// Determine how many objects were destroyed
 				engine->GetGCStatistics(&gcSize3);
				m_numGCObjectsDestroyed += gcSize3 - gcSize2;
			}

			// TODO: If more objects are created per execution than destroyed on average
			//       then it may be necessary to run more iterations of the detection of
			//       cyclic references. At the startup of an application there is usually
			//       a lot of objects created that will live on through out the application
			//       so the average number of objects created per execution will be higher
			//       than the number of destroyed objects in the beginning, but afterwards
			//       it usually levels out to be more or less equal.

			// Just run an incremental step for detecting cyclic references
			engine->GarbageCollect(asGC_ONE_STEP | asGC_DETECT_GARBAGE);
		}
	}

	return int(m_threads.size());
}

void CContextMgr::DoneWithContext(asIScriptContext *ctx)
{
	ctx->GetEngine()->ReturnContext(ctx);
}

void CContextMgr::NextCoRoutine()
{
	m_threads[m_currentThread]->currentCoRoutine++;
	if( m_threads[m_currentThread]->currentCoRoutine >= m_threads[m_currentThread]->coRoutines.size() )
		m_threads[m_currentThread]->currentCoRoutine = 0;
}

void CContextMgr::AbortAll()
{
	// Abort all contexts and release them. The script engine will make
	// sure that all resources held by the scripts are properly released.

	for( asUINT n = 0; n < m_threads.size(); n++ )
	{
		for( asUINT c = 0; c < m_threads[n]->coRoutines.size(); c++ )
		{
			asIScriptContext *ctx = m_threads[n]->coRoutines[c];
			if( ctx )
			{
				ctx->Abort();
				ctx->GetEngine()->ReturnContext(ctx);
				ctx = 0;
			}
		}
		m_threads[n]->coRoutines.resize(0);

		m_freeThreads.push_back(m_threads[n]);
	}

	m_threads.resize(0);

	m_currentThread = 0;
}

asIScriptContext *CContextMgr::AddContext(asIScriptEngine *engine, asIScriptFunction *func, bool keepCtxAfterExec)
{
	// Use RequestContext instead of CreateContext so we can take
	// advantage of possible context pooling configured with the engine
	asIScriptContext *ctx = engine->RequestContext();
	if( ctx == 0 )
		return 0;

	// Prepare it to execute the function
	int r = ctx->Prepare(func);
	if( r < 0 )
	{
		engine->ReturnContext(ctx);
		return 0;
	}

	// Set the context manager as user data with the context so it
	// can be retrieved by the functions registered with the engine
	ctx->SetUserData(this, CONTEXT_MGR);

	// Add the context to the list for execution
	SContextInfo *info = 0;
	if( m_freeThreads.size() > 0 )
	{
		info = *m_freeThreads.rbegin();
		m_freeThreads.pop_back();
	}
	else
	{
		info = new SContextInfo;
	}

	info->coRoutines.push_back(ctx);
	info->currentCoRoutine      = 0;
	info->sleepUntil            = 0;
	info->keepCtxAfterExecution = keepCtxAfterExec ? ctx : 0;
	m_threads.push_back(info);

	return ctx;
}

asIScriptContext *CContextMgr::AddContextForCoRoutine(asIScriptContext *currCtx, asIScriptFunction *func)
{
	asIScriptEngine *engine = currCtx->GetEngine();
	asIScriptContext *coctx = engine->RequestContext();
	if( coctx == 0 )
	{
		return 0;
	}

	// Prepare the context
	int r = coctx->Prepare(func);
	if( r < 0 )
	{
		// Couldn't prepare the context
		engine->ReturnContext(coctx);
		return 0;
	}

	// Set the context manager as user data with the context so it
	// can be retrieved by the functions registered with the engine
	coctx->SetUserData(this, CONTEXT_MGR);

	// Find the current context thread info
	// TODO: Start with the current thread so that we can find the group faster
	for( asUINT n = 0; n < m_threads.size(); n++ )
	{
		if( m_threads[n]->coRoutines[m_threads[n]->currentCoRoutine] == currCtx )
		{
			// Add the coRoutine to the list
			m_threads[n]->coRoutines.push_back(coctx);
		}
	}

	return coctx;
}

void CContextMgr::SetSleeping(asIScriptContext *ctx, asUINT milliSeconds)
{
	assert( m_getTimeFunc != 0 );

	// Find the context and update the timeStamp
	// for when the context is to be continued

	// TODO: Start with the current thread

	for( asUINT n = 0; n < m_threads.size(); n++ )
	{
		if( m_threads[n]->coRoutines[m_threads[n]->currentCoRoutine] == ctx )
		{
			m_threads[n]->sleepUntil = (m_getTimeFunc ? m_getTimeFunc() : 0) + milliSeconds;
		}
	}
}

void CContextMgr::RegisterThreadSupport(asIScriptEngine *engine)
{
	int r;

	// Must set the get time callback function for this to work
	assert( m_getTimeFunc != 0 );

	// Register the sleep function
	r = engine->RegisterGlobalFunction("void sleep(uint)", asFUNCTION(ScriptSleep), asCALL_CDECL); assert( r >= 0 );

	// TODO: Add support for spawning new threads, waiting for signals, etc
}

void CContextMgr::RegisterCoRoutineSupport(asIScriptEngine *engine)
{
	int r;

	// The dictionary add-on must have been registered already
	assert( engine->GetTypeInfoByDecl("dictionary") );

#ifndef AS_MAX_PORTABILITY
	r = engine->RegisterGlobalFunction("void yield()", asFUNCTION(ScriptYield), asCALL_CDECL); assert( r >= 0 );
	r = engine->RegisterFuncdef("void coroutine(dictionary@)");
	r = engine->RegisterGlobalFunction("void createCoRoutine(coroutine @+, dictionary @+)", asFUNCTION(ScriptCreateCoRoutine), asCALL_CDECL); assert( r >= 0 );
#else
	r = engine->RegisterGlobalFunction("void yield()", asFUNCTION(ScriptYield_generic), asCALL_GENERIC); assert( r >= 0 );
	r = engine->RegisterFuncdef("void coroutine(dictionary@)");
	r = engine->RegisterGlobalFunction("void createCoRoutine(coroutine @+, dictionary @+)", asFUNCTION(ScriptCreateCoRoutine_generic), asCALL_GENERIC); assert( r >= 0 );
#endif
}

void CContextMgr::SetGetTimeCallback(TIMEFUNC_t func)
{
	m_getTimeFunc = func;
}

END_AS_NAMESPACE


code:
#ifndef CONTEXTMGR_H
#define CONTEXTMGR_H

// The context manager simplifies the management of multiple concurrent scripts

// More than one context manager can be used, if you wish to control different
// groups of scripts separately, e.g. game object scripts, and GUI scripts.

// OBSERVATION: This class is currently not thread safe.

#ifndef ANGELSCRIPT_H
// Avoid having to inform include path if header is already include before
#include <angelscript.h>
#endif

#include <vector>

BEGIN_AS_NAMESPACE

class CScriptDictionary;

// The internal structure for holding contexts
struct SContextInfo;

// The signature of the get time callback function
typedef asUINT (*TIMEFUNC_t)();

class CContextMgr
{
public:
	CContextMgr();
	~CContextMgr();

	// Set the function that the manager will use to obtain the time in milliseconds
	void SetGetTimeCallback(TIMEFUNC_t func);

	// Registers the following:
	//
	//  void sleep(uint milliseconds)
	//
	// The application must set the get time callback for this to work
	void RegisterThreadSupport(asIScriptEngine *engine);

	// Registers the following:
	//
	//  funcdef void coroutine(dictionary@)
	//  void createCoRoutine(coroutine @func, dictionary @args)
	//  void yield()
	void RegisterCoRoutineSupport(asIScriptEngine *engine);

	// Create a new context, prepare it with the function id, then return
	// it so that the application can pass the argument values. The context
	// will be released by the manager after the execution has completed.
	// Set keepCtxAfterExecution to true if the application needs to retrieve
	// information from the context after it the script has finished.
	asIScriptContext *AddContext(asIScriptEngine *engine, asIScriptFunction *func, bool keepCtxAfterExecution = false);

	// If the context was kept after the execution, this method must be
	// called when the application is done with the context so it can be
	// returned to the pool for reuse.
	void DoneWithContext(asIScriptContext *ctx);

	// Create a new context, prepare it with the function id, then return
	// it so that the application can pass the argument values. The context
	// will be added as a co-routine in the same thread as the currCtx.
	asIScriptContext *AddContextForCoRoutine(asIScriptContext *currCtx, asIScriptFunction *func);

	// Execute each script that is not currently sleeping. The function returns after
	// each script has been executed once. The application should call this function
	// for each iteration of the message pump, or game loop, or whatever.
	// Returns the number of scripts still in execution.
	int ExecuteScripts();

	// Put a script to sleep for a while
	void SetSleeping(asIScriptContext *ctx, asUINT milliSeconds);

	// Switch the execution to the next co-routine in the group.
	// Returns true if the switch was successful.
	void NextCoRoutine();

	// Abort all scripts
	void AbortAll();

protected:
	std::vector<SContextInfo*> m_threads;
	std::vector<SContextInfo*> m_freeThreads;
	asUINT                     m_currentThread;
	TIMEFUNC_t                 m_getTimeFunc;

	// Statistics for Garbage Collection
	asUINT   m_numExecutions;
	asUINT   m_numGCObjectsCreated;
	asUINT   m_numGCObjectsDestroyed;
};

END_AS_NAMESPACE

#endif


code:
#include "datetime.h"
#include "../autowrapper/aswrappedcall.h"
#include <string.h>
#include <assert.h>
#include <new>

using namespace std;
using namespace std::chrono;

BEGIN_AS_NAMESPACE

// TODO: Allow setting the timezone to use

static tm time_point_to_tm(const std::chrono::time_point<std::chrono::system_clock> &tp)
{
	time_t t = system_clock::to_time_t(tp);
	tm local;

	// Use the universal timezone
#ifdef _MSC_VER
	gmtime_s(&local, &t);
#else
	// TODO: gmtime is not threadsafe
	local = *gmtime(&t);
#endif
	return local;
}

// Returns true if successful. Doesn't modify tp if not successful
static bool tm_to_time_point(const tm &_tm, std::chrono::time_point<std::chrono::system_clock> &tp)
{
	tm localTm = _tm;

	// Do not rely on timezone, as it is not portable
	// ref: https://stackoverflow.com/questions/38298261/why-there-is-no-inverse-function-for-gmtime-in-libc
	// ref: https://stackoverflow.com/questions/8558919/mktime-and-tm-isdst
	// TODO: mktime is not threadsafe
	time_t t = mktime(&localTm);
	if (t == -1)
		return false;

	// Adjust the time_t since epoch with the difference of the local timezone to the universal timezone
	// TODO: localtime, gmtime, and mktime are not threadsafe
	t += (mktime(localtime(&t)) - mktime(gmtime(&t)));

	tp = system_clock::from_time_t(t);
	return true;
}

CDateTime::CDateTime() : tp(std::chrono::system_clock::now())
{
}

CDateTime::CDateTime(const CDateTime &o) : tp(o.tp)
{
}

CDateTime &CDateTime::operator=(const CDateTime &o)
{
	tp = o.tp;
	return *this;
}

asUINT CDateTime::getYear() const
{
	tm local = time_point_to_tm(tp);
	return local.tm_year + 1900;
}

asUINT CDateTime::getMonth() const
{
	tm local = time_point_to_tm(tp);
	return local.tm_mon + 1;
}

asUINT CDateTime::getDay() const
{
	tm local = time_point_to_tm(tp);
	return local.tm_mday;
}

asUINT CDateTime::getHour() const
{
	tm local = time_point_to_tm(tp);
	return local.tm_hour;
}

asUINT CDateTime::getMinute() const
{
	tm local = time_point_to_tm(tp);
	return local.tm_min;
}

asUINT CDateTime::getSecond() const
{
	tm local = time_point_to_tm(tp);
	return local.tm_sec;
}

asUINT CDateTime::getWeekDay() const
{
	tm local = time_point_to_tm(tp);
	return local.tm_wday;
}

bool CDateTime::setDate(asUINT year, asUINT month, asUINT day)
{
	tm local = time_point_to_tm(tp);
	local.tm_year = int(year) - 1900;
	local.tm_mon = month - 1;
	local.tm_mday = day;

	std::chrono::time_point<std::chrono::system_clock> newTp;
	if (!tm_to_time_point(local, newTp))
		return false;

	// Check if the date was actually valid
	tm local2 = time_point_to_tm(newTp);

	if (local.tm_year != local2.tm_year ||
		local.tm_mon != local2.tm_mon ||
		local.tm_mday != local2.tm_mday)
		return false;

	tp = newTp;
	return true;
}

bool CDateTime::setTime(asUINT hour, asUINT minute, asUINT second)
{
	tm local = time_point_to_tm(tp);
	local.tm_hour = hour;
	local.tm_min = minute;
	local.tm_sec = second;

	std::chrono::time_point<std::chrono::system_clock> newTp;
	if (!tm_to_time_point(local, newTp))
		return false;

	// Check if the time was actually valid
	tm local2 = time_point_to_tm(newTp);

	if (local.tm_hour != local2.tm_hour ||
		local.tm_min != local2.tm_min ||
		local.tm_sec != local2.tm_sec)
		return false;

	tp = newTp;
	return true;
}

CDateTime::CDateTime(asUINT year, asUINT month, asUINT day, asUINT hour, asUINT minute, asUINT second)
{
	tp = std::chrono::system_clock::now();
	setDate(year, month, day);
	setTime(hour, minute, second);
}

asINT64 CDateTime::operator-(const CDateTime &dt) const
{
	return (tp - dt.tp).count() / std::chrono::system_clock::period::den * std::chrono::system_clock::period::num;
}

CDateTime CDateTime::operator+(asINT64 seconds) const
{
	CDateTime dt(*this);
	dt.tp += std::chrono::system_clock::duration(seconds * std::chrono::system_clock::period::den / std::chrono::system_clock::period::num);
	return dt;
}

CDateTime &CDateTime::operator+=(asINT64 seconds)
{
	tp += std::chrono::system_clock::duration(seconds * std::chrono::system_clock::period::den / std::chrono::system_clock::period::num);
	return *this;
}

CDateTime operator+(asINT64 seconds, const CDateTime &other)
{
	return other + seconds;
}

CDateTime CDateTime::operator-(asINT64 seconds) const
{
	return *this + -seconds;
}

CDateTime &CDateTime::operator-=(asINT64 seconds)
{
	return *this += -seconds;
}

CDateTime operator-(asINT64 seconds, const CDateTime &other)
{
	return other + -seconds;
}

bool CDateTime::operator==(const CDateTime &other) const
{
	return tp == other.tp;
}

bool CDateTime::operator<(const CDateTime &other) const
{
	return tp < other.tp;
}

static int opCmp(const CDateTime &a, const CDateTime &b)
{
	if (a < b) return -1;
	if (a == b) return 0;
	return 1;
}

static void Construct(CDateTime *mem)
{
	new(mem) CDateTime();
}

static void ConstructCopy(CDateTime *mem, const CDateTime &o)
{
	new(mem) CDateTime(o);
}

static void ConstructSet(CDateTime *mem, asUINT year, asUINT month, asUINT day, asUINT hour, asUINT minute, asUINT second)
{
	new(mem) CDateTime(year, month, day, hour, minute, second);
}

static void ConstructSet_Generic(asIScriptGeneric *gen)
{
    CDateTime *date = (CDateTime*)gen->GetObject();
    asUINT year = *(asUINT*)gen->GetAddressOfArg(0);
    asUINT month = *(asUINT*)gen->GetAddressOfArg(1);
    asUINT day = *(asUINT*)gen->GetAddressOfArg(2);
    asUINT hour = *(asUINT*)gen->GetAddressOfArg(3);
    asUINT minute = *(asUINT*)gen->GetAddressOfArg(4);
    asUINT second = *(asUINT*)gen->GetAddressOfArg(5);
    ConstructSet(date, year, month, day, hour, minute, second);
}

void RegisterScriptDateTime(asIScriptEngine *engine)
{
	int r = engine->RegisterObjectType("datetime", sizeof(CDateTime), asOBJ_VALUE | asOBJ_POD | asGetTypeTraits<CDateTime>()); assert(r >= 0);

	if(strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY")==0)
	{
		r = engine->RegisterObjectBehaviour("datetime", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(Construct), asCALL_CDECL_OBJLAST); assert(r >= 0);
		r = engine->RegisterObjectBehaviour("datetime", asBEHAVE_CONSTRUCT, "void f(const datetime &in)", asFUNCTION(ConstructCopy), asCALL_CDECL_OBJFIRST); assert(r >= 0);
		r = engine->RegisterObjectBehaviour("datetime", asBEHAVE_CONSTRUCT, "void f(uint, uint, uint, uint = 0, uint = 0, uint = 0)", asFUNCTION(ConstructSet), asCALL_CDECL_OBJFIRST); assert(r >= 0);
		r = engine->RegisterObjectMethod("datetime", "datetime &opAssign(const datetime &in)", asMETHOD(CDateTime, operator=), asCALL_THISCALL); assert(r >= 0);
		r = engine->RegisterObjectMethod("datetime", "uint get_year() const property", asMETHOD(CDateTime, getYear), asCALL_THISCALL); assert(r >= 0);
		r = engine->RegisterObjectMethod("datetime", "uint get_month() const property", asMETHOD(CDateTime, getMonth), asCALL_THISCALL); assert(r >= 0);
		r = engine->RegisterObjectMethod("datetime", "uint get_day() const property", asMETHOD(CDateTime, getDay), asCALL_THISCALL); assert(r >= 0);
		r = engine->RegisterObjectMethod("datetime", "uint get_hour() const property", asMETHOD(CDateTime, getHour), asCALL_THISCALL); assert(r >= 0);
		r = engine->RegisterObjectMethod("datetime", "uint get_minute() const property", asMETHOD(CDateTime, getMinute), asCALL_THISCALL); assert(r >= 0);
		r = engine->RegisterObjectMethod("datetime", "uint get_second() const property", asMETHOD(CDateTime, getSecond), asCALL_THISCALL); assert(r >= 0);
		r = engine->RegisterObjectMethod("datetime", "uint get_weekDay() const property", asMETHOD(CDateTime, getWeekDay), asCALL_THISCALL); assert(r >= 0);
		r = engine->RegisterObjectMethod("datetime", "bool setDate(uint year, uint month, uint day)", asMETHOD(CDateTime, setDate), asCALL_THISCALL); assert(r >= 0);
		r = engine->RegisterObjectMethod("datetime", "bool setTime(uint hour, uint minute, uint second)", asMETHOD(CDateTime, setTime), asCALL_THISCALL); assert(r >= 0);
		r = engine->RegisterObjectMethod("datetime", "int64 opSub(const datetime &in) const", asMETHODPR(CDateTime, operator-, (const CDateTime &other) const, asINT64), asCALL_THISCALL); assert(r >= 0);
		r = engine->RegisterObjectMethod("datetime", "datetime opAdd(int64 seconds) const", asMETHOD(CDateTime, operator+), asCALL_THISCALL); assert(r >= 0);
		r = engine->RegisterObjectMethod("datetime", "datetime opAdd_r(int64 seconds) const", asFUNCTIONPR(operator+, (asINT64 seconds, const CDateTime &other), CDateTime), asCALL_CDECL_OBJLAST); assert(r >= 0);
		r = engine->RegisterObjectMethod("datetime", "datetime &opAddAssign(int64 seconds)", asMETHOD(CDateTime, operator+=), asCALL_THISCALL); assert(r >= 0);
		r = engine->RegisterObjectMethod("datetime", "datetime opSub(int64 seconds) const", asMETHODPR(CDateTime, operator-, (asINT64) const, CDateTime), asCALL_THISCALL); assert(r >= 0);
		r = engine->RegisterObjectMethod("datetime", "datetime opSub_r(int64 seconds) const", asFUNCTIONPR(operator-, (asINT64 seconds, const CDateTime &other), CDateTime), asCALL_CDECL_OBJLAST); assert(r >= 0);
		r = engine->RegisterObjectMethod("datetime", "datetime &opSubAssign(int64 seconds)", asMETHOD(CDateTime, operator-=), asCALL_THISCALL); assert(r >= 0);
		r = engine->RegisterObjectMethod("datetime", "bool opEquals(const datetime &in) const", asMETHODPR(CDateTime, operator==, (const CDateTime &other) const, bool), asCALL_THISCALL); assert(r >= 0);
		r = engine->RegisterObjectMethod("datetime", "int opCmp(const datetime &in) const", asFUNCTION(opCmp), asCALL_CDECL_OBJFIRST); assert(r >= 0);
	}
	else
	{
		r = engine->RegisterObjectBehaviour("datetime", asBEHAVE_CONSTRUCT, "void f()", WRAP_OBJ_LAST(Construct), asCALL_GENERIC); assert(r >= 0);
		r = engine->RegisterObjectBehaviour("datetime", asBEHAVE_CONSTRUCT, "void f(const datetime &in)", WRAP_OBJ_FIRST(ConstructCopy), asCALL_GENERIC); assert(r >= 0);
		r = engine->RegisterObjectBehaviour("datetime", asBEHAVE_CONSTRUCT, "void f(uint, uint, uint, uint = 0, uint = 0, uint = 0)", asFUNCTION(ConstructSet_Generic), asCALL_GENERIC); assert(r >= 0);
		r = engine->RegisterObjectMethod("datetime", "datetime &opAssign(const datetime &in)", WRAP_MFN(CDateTime, operator=), asCALL_GENERIC); assert(r >= 0);
		r = engine->RegisterObjectMethod("datetime", "uint get_year() const property", WRAP_MFN(CDateTime, getYear), asCALL_GENERIC); assert(r >= 0);
		r = engine->RegisterObjectMethod("datetime", "uint get_month() const property", WRAP_MFN(CDateTime, getMonth), asCALL_GENERIC); assert(r >= 0);
		r = engine->RegisterObjectMethod("datetime", "uint get_day() const property", WRAP_MFN(CDateTime, getDay), asCALL_GENERIC); assert(r >= 0);
		r = engine->RegisterObjectMethod("datetime", "uint get_hour() const property", WRAP_MFN(CDateTime, getHour), asCALL_GENERIC); assert(r >= 0);
		r = engine->RegisterObjectMethod("datetime", "uint get_minute() const property", WRAP_MFN(CDateTime, getMinute), asCALL_GENERIC); assert(r >= 0);
		r = engine->RegisterObjectMethod("datetime", "uint get_second() const property", WRAP_MFN(CDateTime, getSecond), asCALL_GENERIC); assert(r >= 0);
		r = engine->RegisterObjectMethod("datetime", "uint get_weekDay() const property", WRAP_MFN(CDateTime, getWeekDay), asCALL_GENERIC); assert(r >= 0);
		r = engine->RegisterObjectMethod("datetime", "bool setDate(uint year, uint month, uint day)", WRAP_MFN(CDateTime, setDate), asCALL_GENERIC); assert(r >= 0);
		r = engine->RegisterObjectMethod("datetime", "bool setTime(uint hour, uint minute, uint second)", WRAP_MFN(CDateTime, setTime), asCALL_GENERIC); assert(r >= 0);
		r = engine->RegisterObjectMethod("datetime", "int64 opSub(const datetime &in) const", WRAP_MFN_PR(CDateTime, operator-, (const CDateTime &other) const, asINT64), asCALL_GENERIC); assert(r >= 0);
		r = engine->RegisterObjectMethod("datetime", "datetime opAdd(int64 seconds) const", WRAP_MFN(CDateTime, operator+), asCALL_GENERIC); assert(r >= 0);
		r = engine->RegisterObjectMethod("datetime", "datetime opAdd_r(int64 seconds) const", WRAP_OBJ_LAST_PR(operator+, (asINT64 seconds, const CDateTime &other), CDateTime), asCALL_GENERIC); assert(r >= 0);
		r = engine->RegisterObjectMethod("datetime", "datetime &opAddAssign(int64 seconds)", WRAP_MFN(CDateTime, operator+=), asCALL_GENERIC); assert(r >= 0);
		r = engine->RegisterObjectMethod("datetime", "datetime opSub(int64 seconds) const", WRAP_MFN_PR(CDateTime, operator-, (asINT64) const, CDateTime), asCALL_GENERIC); assert(r >= 0);
		r = engine->RegisterObjectMethod("datetime", "datetime opSub_r(int64 seconds) const", WRAP_OBJ_LAST_PR(operator-, (asINT64 seconds, const CDateTime &other), CDateTime), asCALL_GENERIC); assert(r >= 0);
		r = engine->RegisterObjectMethod("datetime", "datetime &opSubAssign(int64 seconds)", WRAP_MFN(CDateTime, operator-=), asCALL_GENERIC); assert(r >= 0);
		r = engine->RegisterObjectMethod("datetime", "bool opEquals(const datetime &in) const", WRAP_MFN_PR(CDateTime, operator==, (const CDateTime &other) const, bool), asCALL_GENERIC); assert(r >= 0);
		r = engine->RegisterObjectMethod("datetime", "int opCmp(const datetime &in) const", WRAP_OBJ_FIRST(opCmp), asCALL_GENERIC); assert(r >= 0);
	}
}

END_AS_NAMESPACE


code:
#ifndef SCRIPTDATETIME_H
#define SCRIPTDATETIME_H

#ifndef ANGELSCRIPT_H
// Avoid having to inform include path if header is already include before
#include <angelscript.h>
#endif

#ifdef AS_CAN_USE_CPP11
#include <chrono>
#else
#error Sorry, this requires C++11 which your compiler doesnt appear to support
#endif

BEGIN_AS_NAMESPACE

class CDateTime
{
public:
	// Constructors
	CDateTime();
	CDateTime(const CDateTime &other);
	CDateTime(asUINT year, asUINT month, asUINT day, asUINT hour, asUINT minute, asUINT second);

	// Copy the stored value from another any object
	CDateTime &operator=(const CDateTime &other);

	// Accessors
	asUINT getYear() const;
	asUINT getMonth() const;
	asUINT getDay() const;
	asUINT getHour() const;
	asUINT getMinute() const;
	asUINT getSecond() const;
	asUINT getWeekDay() const;

	// Setters
	// Returns true if valid
	bool setDate(asUINT year, asUINT month, asUINT day);
	bool setTime(asUINT hour, asUINT minute, asUINT second);

	// Operators
	// Return difference in seconds
	asINT64          operator-(const CDateTime &other) const;
	CDateTime        operator+(asINT64 seconds) const;
	friend CDateTime operator+(asINT64 seconds, const CDateTime &other);
	CDateTime &      operator+=(asINT64 seconds);
	CDateTime        operator-(asINT64 seconds) const;
	friend CDateTime operator-(asINT64 seconds, const CDateTime &other);
	CDateTime &      operator-=(asINT64 seconds);
	bool             operator==(const CDateTime &other) const;
	bool             operator<(const CDateTime &other) const;

protected:
	std::chrono::system_clock::time_point tp;
};

void RegisterScriptDateTime(asIScriptEngine *engine);

END_AS_NAMESPACE

#endif


code:
#include "debugger.h"
#include <iostream>  // cout
#include <sstream>   // stringstream
#include <stdlib.h>  // atoi
#include <assert.h>  // assert
#include <cstring>   // strlen

using namespace std;

BEGIN_AS_NAMESPACE

CDebugger::CDebugger()
{
	m_action = CONTINUE;
	m_lastFunction = 0;
	m_engine = 0;
}

CDebugger::~CDebugger()
{
	SetEngine(0);
}

string CDebugger::ToString(void *value, asUINT typeId, int expandMembers, asIScriptEngine *engine)
{
	if( value == 0 )
		return "<null>";

	// If no engine pointer was provided use the default
	if( engine == 0 )
		engine = m_engine;

	stringstream s;
	if( typeId == asTYPEID_VOID )
		return "<void>";
	else if( typeId == asTYPEID_BOOL )
		return *(bool*)value ? "true" : "false";
	else if( typeId == asTYPEID_INT8 )
		s << (int)*(signed char*)value;
	else if( typeId == asTYPEID_INT16 )
		s << (int)*(signed short*)value;
	else if( typeId == asTYPEID_INT32 )
		s << *(signed int*)value;
	else if( typeId == asTYPEID_INT64 )
#if defined(_MSC_VER) && _MSC_VER <= 1200
		s << "{...}"; // MSVC6 doesn't like the << operator for 64bit integer
#else
		s << *(asINT64*)value;
#endif
	else if( typeId == asTYPEID_UINT8 )
		s << (unsigned int)*(unsigned char*)value;
	else if( typeId == asTYPEID_UINT16 )
		s << (unsigned int)*(unsigned short*)value;
	else if( typeId == asTYPEID_UINT32 )
		s << *(unsigned int*)value;
	else if( typeId == asTYPEID_UINT64 )
#if defined(_MSC_VER) && _MSC_VER <= 1200
		s << "{...}"; // MSVC6 doesn't like the << operator for 64bit integer
#else
		s << *(asQWORD*)value;
#endif
	else if( typeId == asTYPEID_FLOAT )
		s << *(float*)value;
	else if( typeId == asTYPEID_DOUBLE )
		s << *(double*)value;
	else if( (typeId & asTYPEID_MASK_OBJECT) == 0 )
	{
		// The type is an enum
		s << *(asUINT*)value;

		// Check if the value matches one of the defined enums
		if( engine )
		{
			asITypeInfo *t = engine->GetTypeInfoById(typeId);
			for( int n = t->GetEnumValueCount(); n-- > 0; )
			{
				int enumVal;
				const char *enumName = t->GetEnumValueByIndex(n, &enumVal);
				if( enumVal == *(int*)value )
				{
					s << ", " << enumName;
					break;
				}
			}
		}
	}
	else if( typeId & asTYPEID_SCRIPTOBJECT )
	{
		// Dereference handles, so we can see what it points to
		if( typeId & asTYPEID_OBJHANDLE )
			value = *(void**)value;

		asIScriptObject *obj = (asIScriptObject *)value;

		// Print the address of the object
		s << "{" << obj << "}";

		// Print the members
		if( obj && expandMembers > 0 )
		{
			asITypeInfo *type = obj->GetObjectType();
			for( asUINT n = 0; n < obj->GetPropertyCount(); n++ )
			{
				if( n == 0 )
					s << " ";
				else
					s << ", ";

				s << type->GetPropertyDeclaration(n) << " = " << ToString(obj->GetAddressOfProperty(n), obj->GetPropertyTypeId(n), expandMembers - 1, type->GetEngine());
			}
		}
	}
	else
	{
		// Dereference handles, so we can see what it points to
		if( typeId & asTYPEID_OBJHANDLE )
			value = *(void**)value;

		// Print the address for reference types so it will be
		// possible to see when handles point to the same object
		if( engine )
		{
			asITypeInfo *type = engine->GetTypeInfoById(typeId);
			if( type->GetFlags() & asOBJ_REF )
				s << "{" << value << "}";

			if( value )
			{
				// Check if there is a registered to-string callback
				map<const asITypeInfo*, ToStringCallback>::iterator it = m_toStringCallbacks.find(type);
				if( it == m_toStringCallbacks.end() )
				{
					// If the type is a template instance, there might be a
					// to-string callback for the generic template type
					if( type->GetFlags() & asOBJ_TEMPLATE )
					{
						asITypeInfo *tmplType = engine->GetTypeInfoByName(type->GetName());
						it = m_toStringCallbacks.find(tmplType);
					}
				}

				if( it != m_toStringCallbacks.end() )
				{
					if( type->GetFlags() & asOBJ_REF )
						s << " ";

					// Invoke the callback to get the string representation of this type
					string str = it->second(value, expandMembers, this);
					s << str;
				}
			}
		}
		else
			s << "{no engine}";
	}

	return s.str();
}

void CDebugger::RegisterToStringCallback(const asITypeInfo *ot, ToStringCallback callback)
{
	if( m_toStringCallbacks.find(ot) == m_toStringCallbacks.end() )
		m_toStringCallbacks.insert(map<const asITypeInfo*, ToStringCallback>::value_type(ot, callback));
}

void CDebugger::LineCallback(asIScriptContext *ctx)
{
	assert( ctx );

	// This should never happen, but it doesn't hurt to validate it
	if( ctx == 0 )
		return;

	// By default we ignore callbacks when the context is not active.
	// An application might override this to for example disconnect the
	// debugger as the execution finished.
	if( ctx->GetState() != asEXECUTION_ACTIVE )
		return;

	if( m_action == CONTINUE )
	{
		if( !CheckBreakPoint(ctx) )
			return;
	}
	else if( m_action == STEP_OVER )
	{
		if( ctx->GetCallstackSize() > m_lastCommandAtStackLevel )
		{
			if( !CheckBreakPoint(ctx) )
				return;
		}
	}
	else if( m_action == STEP_OUT )
	{
		if( ctx->GetCallstackSize() >= m_lastCommandAtStackLevel )
		{
			if( !CheckBreakPoint(ctx) )
				return;
		}
	}
	else if( m_action == STEP_INTO )
	{
		CheckBreakPoint(ctx);

		// Always break, but we call the check break point anyway
		// to tell user when break point has been reached
	}

	stringstream s;
	const char *file = 0;
	int lineNbr = ctx->GetLineNumber(0, 0, &file);
	s << (file ? file : "{unnamed}") << ":" << lineNbr << "; " << ctx->GetFunction()->GetDeclaration() << endl;
	Output(s.str());

	TakeCommands(ctx);
}

bool CDebugger::CheckBreakPoint(asIScriptContext *ctx)
{
	if( ctx == 0 )
		return false;

	// TODO: Should cache the break points in a function by checking which possible break points
	//       can be hit when entering a function. If there are no break points in the current function
	//       then there is no need to check every line.

	const char *tmp = 0;
	int lineNbr = ctx->GetLineNumber(0, 0, &tmp);

	// Consider just filename, not the full path
	string file = tmp ? tmp : "";
	size_t r = file.find_last_of("\\/");
	if( r != string::npos )
		file = file.substr(r+1);

	// Did we move into a new function?
	asIScriptFunction *func = ctx->GetFunction();
	if( m_lastFunction != func )
	{
		// Check if any breakpoints need adjusting
		for( size_t n = 0; n < m_breakPoints.size(); n++ )
		{
			// We need to check for a breakpoint at entering the function
			if( m_breakPoints[n].func )
			{
				if( m_breakPoints[n].name == func->GetName() )
				{
					stringstream s;
					s << "Entering function '" << m_breakPoints[n].name << "'. Transforming it into break point" << endl;
					Output(s.str());

					// Transform the function breakpoint into a file breakpoint
					m_breakPoints[n].name           = file;
					m_breakPoints[n].lineNbr        = lineNbr;
					m_breakPoints[n].func           = false;
					m_breakPoints[n].needsAdjusting = false;
				}
			}
			// Check if a given breakpoint fall on a line with code or else adjust it to the next line
			else if( m_breakPoints[n].needsAdjusting &&
					 m_breakPoints[n].name == file )
			{
				int line = func->FindNextLineWithCode(m_breakPoints[n].lineNbr);
				if( line >= 0 )
				{
					m_breakPoints[n].needsAdjusting = false;
					if( line != m_breakPoints[n].lineNbr )
					{
						stringstream s;
						s << "Moving break point " << n << " in file '" << file << "' to next line with code at line " << line << endl;
						Output(s.str());

						// Move the breakpoint to the next line
						m_breakPoints[n].lineNbr = line;
					}
				}
			}
		}
	}
	m_lastFunction = func;

	// Determine if there is a breakpoint at the current line
	for( size_t n = 0; n < m_breakPoints.size(); n++ )
	{
		// TODO: do case-less comparison for file name

		// Should we break?
		if( !m_breakPoints[n].func &&
			m_breakPoints[n].lineNbr == lineNbr &&
			m_breakPoints[n].name == file )
		{
			stringstream s;
			s << "Reached break point " << n << " in file '" << file << "' at line " << lineNbr << endl;
			Output(s.str());
			return true;
		}
	}

	return false;
}

void CDebugger::TakeCommands(asIScriptContext *ctx)
{
	for(;;)
	{
		char buf[512];

		Output("[dbg]> ");
		cin.getline(buf, 512);

		if( InterpretCommand(string(buf), ctx) )
			break;
	}
}

bool CDebugger::InterpretCommand(const string &cmd, asIScriptContext *ctx)
{
	if( cmd.length() == 0 ) return true;

	switch( cmd[0] )
	{
	case 'c':
		m_action = CONTINUE;
		break;

	case 's':
		m_action = STEP_INTO;
		break;

	case 'n':
		m_action = STEP_OVER;
		m_lastCommandAtStackLevel = ctx ? ctx->GetCallstackSize() : 1;
		break;

	case 'o':
		m_action = STEP_OUT;
		m_lastCommandAtStackLevel = ctx ? ctx->GetCallstackSize() : 0;
		break;

	case 'b':
		{
			// Set break point
			size_t p = cmd.find_first_not_of(" \t", 1);
			size_t div = cmd.find(':');
			if( div != string::npos && div > 2 && p > 1 )
			{
				string file = cmd.substr(2, div-2);
				string line = cmd.substr(div+1);

				int nbr = atoi(line.c_str());

				AddFileBreakPoint(file, nbr);
			}
			else if( div == string::npos && p != string::npos && p > 1 )
			{
				string func = cmd.substr(p);

				AddFuncBreakPoint(func);
			}
			else
			{
				Output("Incorrect format for setting break point, expected one of:\n"
				       " b <file name>:<line number>\n"
				       " b <function name>\n");
			}
		}
		// take more commands
		return false;

	case 'r':
		{
			// Remove break point
			size_t p = cmd.find_first_not_of(" \t", 1);
			if( cmd.length() > 2 && p != string::npos && p > 1 )
			{
				string br = cmd.substr(2);
				if( br == "all" )
				{
					m_breakPoints.clear();
					Output("All break points have been removed\n");
				}
				else
				{
					int nbr = atoi(br.c_str());
					if( nbr >= 0 && nbr < (int)m_breakPoints.size() )
						m_breakPoints.erase(m_breakPoints.begin()+nbr);
					ListBreakPoints();
				}
			}
			else
			{
				Output("Incorrect format for removing break points, expected:\n"
				       " r <all|number of break point>\n");
			}
		}
		// take more commands
		return false;

	case 'l':
		{
			// List something
			bool printHelp = false;
			size_t p = cmd.find_first_not_of(" \t", 1);
			if( p != string::npos && p > 1 )
			{
				if( cmd[p] == 'b' )
				{
					ListBreakPoints();
				}
				else if( cmd[p] == 'v' )
				{
					ListLocalVariables(ctx);
				}
				else if( cmd[p] == 'g' )
				{
					ListGlobalVariables(ctx);
				}
				else if( cmd[p] == 'm' )
				{
					ListMemberProperties(ctx);
				}
				else if( cmd[p] == 's' )
				{
					ListStatistics(ctx);
				}
				else
				{
					Output("Unknown list option.\n");
					printHelp = true;
				}
			}
			else
			{
				Output("Incorrect format for list command.\n");
				printHelp = true;
			}

			if( printHelp )
			{
				Output("Expected format: \n"
					   " l <list option>\n"
					   "Available options: \n"
					   " b - breakpoints\n"
					   " v - local variables\n"
					   " m - member properties\n"
					   " g - global variables\n"
					   " s - statistics\n");
			}
		}
		// take more commands
		return false;

	case 'h':
		PrintHelp();
		// take more commands
		return false;

	case 'p':
		{
			// Print a value
			size_t p = cmd.find_first_not_of(" \t", 1);
			if( p != string::npos && p > 1 )
			{
				PrintValue(cmd.substr(p), ctx);
			}
			else
			{
				Output("Incorrect format for print, expected:\n"
					   " p <expression>\n");
			}
		}
		// take more commands
		return false;

	case 'w':
		// Where am I?
		PrintCallstack(ctx);
		// take more commands
		return false;

	case 'a':
		// abort the execution
		if( ctx == 0 )
		{
			Output("No script is running\n");
			return false;
		}
		ctx->Abort();
		break;

	default:
		Output("Unknown command\n");
		// take more commands
		return false;
	}

	// Continue execution
	return true;
}

void CDebugger::PrintValue(const std::string &expr, asIScriptContext *ctx)
{
	if( ctx == 0 )
	{
		Output("No script is running\n");
		return;
	}

	asIScriptEngine *engine = ctx->GetEngine();

	// Tokenize the input string to get the variable scope and name
	asUINT len = 0;
	string scope;
	string name;
	string str = expr;
	asETokenClass t = engine->ParseToken(str.c_str(), 0, &len);
	while( t == asTC_IDENTIFIER || (t == asTC_KEYWORD && len == 2 && str.compare(0, 2, "::") == 0) )
	{
		if( t == asTC_KEYWORD )
		{
			if( scope == "" && name == "" )
				scope = "::";			// global scope
			else if( scope == "::" || scope == "" )
				scope = name;			// namespace
			else
				scope += "::" + name;	// nested namespace
			name = "";
		}
		else if( t == asTC_IDENTIFIER )
			name.assign(str.c_str(), len);

		// Skip the parsed token and get the next one
		str = str.substr(len);
		t = engine->ParseToken(str.c_str(), 0, &len);
	}

	if( name.size() )
	{
		// Find the variable
		void *ptr = 0;
		int typeId = 0;

		asIScriptFunction *func = ctx->GetFunction();
		if( !func ) return;

		// skip local variables if a scope was informed
		if( scope == "" )
		{
			// We start from the end, in case the same name is reused in different scopes
			for( asUINT n = func->GetVarCount(); n-- > 0; )
			{
				const char* varName = 0;
				ctx->GetVar(n, 0, &varName, &typeId);
				if( ctx->IsVarInScope(n) && varName != 0 && name == varName )
				{
					ptr = ctx->GetAddressOfVar(n);
					break;
				}
			}

			// Look for class members, if we're in a class method
			if( !ptr && func->GetObjectType() )
			{
				if( name == "this" )
				{
					ptr = ctx->GetThisPointer();
					typeId = ctx->GetThisTypeId();
				}
				else
				{
					asITypeInfo *type = engine->GetTypeInfoById(ctx->GetThisTypeId());
					for( asUINT n = 0; n < type->GetPropertyCount(); n++ )
					{
						const char *propName = 0;
						int offset = 0;
						bool isReference = 0;
						int compositeOffset = 0;
						bool isCompositeIndirect = false;
						type->GetProperty(n, &propName, &typeId, 0, 0, &offset, &isReference, 0, &compositeOffset, &isCompositeIndirect);
						if( name == propName )
						{
							ptr = (void*)(((asBYTE*)ctx->GetThisPointer())+compositeOffset);
							if (isCompositeIndirect) ptr = *(void**)ptr;
							ptr = (void*)(((asBYTE*)ptr) + offset);
							if( isReference ) ptr = *(void**)ptr;
							break;
						}
					}
				}
			}
		}

		// Look for global variables
		if( !ptr )
		{
			if( scope == "" )
			{
				// If no explicit scope was informed then use the namespace of the current function by default
				scope = func->GetNamespace();
			}
			else if( scope == "::" )
			{
				// The global namespace will be empty
				scope = "";
			}

			asIScriptModule *mod = func->GetModule();
			if( mod )
			{
				for( asUINT n = 0; n < mod->GetGlobalVarCount(); n++ )
				{
					const char *varName = 0, *nameSpace = 0;
					mod->GetGlobalVar(n, &varName, &nameSpace, &typeId);

					// Check if both name and namespace match
					if( name == varName && scope == nameSpace )
					{
						ptr = mod->GetAddressOfGlobalVar(n);
						break;
					}
				}
			}
		}

		if( ptr )
		{
			// TODO: If there is a . after the identifier, check for members
			// TODO: If there is a [ after the identifier try to call the 'opIndex(expr) const' method
			if( str != "" )
			{
				Output("Invalid expression. Expression doesn't end after symbol\n");
			}
			else
			{
				stringstream s;
				// TODO: Allow user to set if members should be expanded
				// Expand members by default to 3 recursive levels only
				s << ToString(ptr, typeId, 3, engine) << endl;
				Output(s.str());
			}
		}
		else
		{
			Output("Invalid expression. No matching symbol\n");
		}
	}
	else
	{
		Output("Invalid expression. Expected identifier\n");
	}
}

void CDebugger::ListBreakPoints()
{
	// List all break points
	stringstream s;
	for( size_t b = 0; b < m_breakPoints.size(); b++ )
		if( m_breakPoints[b].func )
			s << b << " - " << m_breakPoints[b].name << endl;
		else
			s << b << " - " << m_breakPoints[b].name << ":" << m_breakPoints[b].lineNbr << endl;
	Output(s.str());
}

void CDebugger::ListMemberProperties(asIScriptContext *ctx)
{
	if( ctx == 0 )
	{
		Output("No script is running\n");
		return;
	}

	void *ptr = ctx->GetThisPointer();
	if( ptr )
	{
		stringstream s;
		// TODO: Allow user to define if members should be expanded or not
		// Expand members by default to 3 recursive levels only
		s << "this = " << ToString(ptr, ctx->GetThisTypeId(), 3, ctx->GetEngine()) << endl;
		Output(s.str());
	}
}

void CDebugger::ListLocalVariables(asIScriptContext *ctx)
{
	if( ctx == 0 )
	{
		Output("No script is running\n");
		return;
	}

	asIScriptFunction *func = ctx->GetFunction();
	if( !func ) return;

	stringstream s;
	for( asUINT n = 0; n < func->GetVarCount(); n++ )
	{
		// Skip temporary variables
		// TODO: Should there be an option to view temporary variables too?
		const char* name;
		func->GetVar(n, &name);
		if (name == 0 || strlen(name) == 0)
			continue;

		if( ctx->IsVarInScope(n) )
		{
			// TODO: Allow user to set if members should be expanded or not
			// Expand members by default to 3 recursive levels only
			int typeId;
			ctx->GetVar(n, 0, 0, &typeId);
			s << func->GetVarDecl(n) << " = " << ToString(ctx->GetAddressOfVar(n), typeId, 3, ctx->GetEngine()) << endl;
		}
	}
	Output(s.str());
}

void CDebugger::ListGlobalVariables(asIScriptContext *ctx)
{
	if( ctx == 0 )
	{
		Output("No script is running\n");
		return;
	}

	// Determine the current module from the function
	asIScriptFunction *func = ctx->GetFunction();
	if( !func ) return;

	asIScriptModule *mod = func->GetModule();
	if( !mod ) return;

	stringstream s;
	for( asUINT n = 0; n < mod->GetGlobalVarCount(); n++ )
	{
		int typeId = 0;
		mod->GetGlobalVar(n, 0, 0, &typeId);
		// TODO: Allow user to set how many recursive expansions should be done
		// Expand members by default to 3 recursive levels only
		s << mod->GetGlobalVarDeclaration(n) << " = " << ToString(mod->GetAddressOfGlobalVar(n), typeId, 3, ctx->GetEngine()) << endl;
	}
	Output(s.str());
}

void CDebugger::ListStatistics(asIScriptContext *ctx)
{
	if( ctx == 0 )
	{
		Output("No script is running\n");
		return;
	}

	asIScriptEngine *engine = ctx->GetEngine();

	asUINT gcCurrSize, gcTotalDestr, gcTotalDet, gcNewObjects, gcTotalNewDestr;
	engine->GetGCStatistics(&gcCurrSize, &gcTotalDestr, &gcTotalDet, &gcNewObjects, &gcTotalNewDestr);

	stringstream s;
	s << "Garbage collector:" << endl;
	s << " current size:          " << gcCurrSize << endl;
	s << " total destroyed:       " << gcTotalDestr << endl;
	s << " total detected:        " << gcTotalDet << endl;
	s << " new objects:           " << gcNewObjects << endl;
	s << " new objects destroyed: " << gcTotalNewDestr << endl;

	Output(s.str());
}

void CDebugger::PrintCallstack(asIScriptContext *ctx)
{
	if( ctx == 0 )
	{
		Output("No script is running\n");
		return;
	}

	stringstream s;
	const char *file = 0;
	int lineNbr = 0;
	for( asUINT n = 0; n < ctx->GetCallstackSize(); n++ )
	{
		lineNbr = ctx->GetLineNumber(n, 0, &file);
		s << (file ? file : "{unnamed}") << ":" << lineNbr << "; " << ctx->GetFunction(n)->GetDeclaration() << endl;
	}
	Output(s.str());
}

void CDebugger::AddFuncBreakPoint(const string &func)
{
	// Trim the function name
	size_t b = func.find_first_not_of(" \t");
	size_t e = func.find_last_not_of(" \t");
	string actual = func.substr(b, e != string::npos ? e-b+1 : string::npos);

	stringstream s;
	s << "Adding deferred break point for function '" << actual << "'" << endl;
	Output(s.str());

	BreakPoint bp(actual, 0, true);
	m_breakPoints.push_back(bp);
}

void CDebugger::AddFileBreakPoint(const string &file, int lineNbr)
{
	// Store just file name, not entire path
	size_t r = file.find_last_of("\\/");
	string actual;
	if( r != string::npos )
		actual = file.substr(r+1);
	else
		actual = file;

	// Trim the file name
	size_t b = actual.find_first_not_of(" \t");
	size_t e = actual.find_last_not_of(" \t");
	actual = actual.substr(b, e != string::npos ? e-b+1 : string::npos);

	stringstream s;
	s << "Setting break point in file '" << actual << "' at line " << lineNbr << endl;
	Output(s.str());

	BreakPoint bp(actual, lineNbr, false);
	m_breakPoints.push_back(bp);
}

void CDebugger::PrintHelp()
{
	Output(" c - Continue\n"
	       " s - Step into\n"
	       " n - Next step\n"
	       " o - Step out\n"
	       " b - Set break point\n"
	       " l - List various things\n"
	       " r - Remove break point\n"
	       " p - Print value\n"
	       " w - Where am I?\n"
	       " a - Abort execution\n"
	       " h - Print this help text\n");
}

void CDebugger::Output(const string &str)
{
	// By default we just output to stdout
	cout << str;
}

void CDebugger::SetEngine(asIScriptEngine *engine)
{
	if( m_engine != engine )
	{
		if( m_engine )
			m_engine->Release();
		m_engine = engine;
		if( m_engine )
			m_engine->AddRef();
	}
}

asIScriptEngine *CDebugger::GetEngine()
{
	return m_engine;
}

END_AS_NAMESPACE


code:
#ifndef DEBUGGER_H
#define DEBUGGER_H

#ifndef ANGELSCRIPT_H
// Avoid having to inform include path if header is already include before
#include <angelscript.h>
#endif

#include <string>
#include <vector>
#include <map>

BEGIN_AS_NAMESPACE

class CDebugger
{
public:
	CDebugger();
	virtual ~CDebugger();

	// Register callbacks to handle to-string conversions of application types
	// The expandMembersLevel is a counter for how many recursive levels the members should be expanded.
	// If the object that is being converted to a string has members of its own the callback should call
	// the debugger's ToString passing in expandMembersLevel - 1.
	typedef std::string (*ToStringCallback)(void *obj, int expandMembersLevel, CDebugger *dbg);
	virtual void RegisterToStringCallback(const asITypeInfo *ti, ToStringCallback callback);

	// User interaction
	virtual void TakeCommands(asIScriptContext *ctx);
	virtual void Output(const std::string &str);

	// Line callback invoked by context
	virtual void LineCallback(asIScriptContext *ctx);

	// Commands
	virtual void PrintHelp();
	virtual void AddFileBreakPoint(const std::string &file, int lineNbr);
	virtual void AddFuncBreakPoint(const std::string &func);
	virtual void ListBreakPoints();
	virtual void ListLocalVariables(asIScriptContext *ctx);
	virtual void ListGlobalVariables(asIScriptContext *ctx);
	virtual void ListMemberProperties(asIScriptContext *ctx);
	virtual void ListStatistics(asIScriptContext *ctx);
	virtual void PrintCallstack(asIScriptContext *ctx);
	virtual void PrintValue(const std::string &expr, asIScriptContext *ctx);

	// Helpers
	virtual bool InterpretCommand(const std::string &cmd, asIScriptContext *ctx);
	virtual bool CheckBreakPoint(asIScriptContext *ctx);
	virtual std::string ToString(void *value, asUINT typeId, int expandMembersLevel, asIScriptEngine *engine);

	// Optionally set the engine pointer in the debugger so it can be retrieved
	// by callbacks that need it. This will hold a reference to the engine.
	virtual void SetEngine(asIScriptEngine *engine);
	virtual asIScriptEngine *GetEngine();

protected:
	enum DebugAction
	{
		CONTINUE,  // continue until next break point
		STEP_INTO, // stop at next instruction
		STEP_OVER, // stop at next instruction, skipping called functions
		STEP_OUT   // run until returning from current function
	};
	DebugAction        m_action;
	asUINT             m_lastCommandAtStackLevel;
	asIScriptFunction *m_lastFunction;

	struct BreakPoint
	{
		BreakPoint(std::string f, int n, bool _func) : name(f), lineNbr(n), func(_func), needsAdjusting(true) {}
		std::string name;
		int         lineNbr;
		bool        func;
		bool        needsAdjusting;
	};
	std::vector<BreakPoint> m_breakPoints;

	asIScriptEngine *m_engine;

	// Registered callbacks for converting types to strings
	std::map<const asITypeInfo*, ToStringCallback> m_toStringCallbacks;
};

END_AS_NAMESPACE

#endif


code:
#include "scriptany.h"
#include <new>
#include <assert.h>
#include <string.h>

BEGIN_AS_NAMESPACE

// We'll use the generic interface for the factories as we need the engine pointer
static void ScriptAnyFactory_Generic(asIScriptGeneric *gen)
{
	asIScriptEngine *engine = gen->GetEngine();

	*(CScriptAny**)gen->GetAddressOfReturnLocation() = new CScriptAny(engine);
}

static void ScriptAnyFactory2_Generic(asIScriptGeneric *gen)
{
	asIScriptEngine *engine = gen->GetEngine();
	void *ref = (void*)gen->GetArgAddress(0);
	int refType = gen->GetArgTypeId(0);

	*(CScriptAny**)gen->GetAddressOfReturnLocation() = new CScriptAny(ref,refType,engine);
}

static CScriptAny &ScriptAnyAssignment(CScriptAny *other, CScriptAny *self)
{
	return *self = *other;
}

static void ScriptAnyAssignment_Generic(asIScriptGeneric *gen)
{
	CScriptAny *other = (CScriptAny*)gen->GetArgObject(0);
	CScriptAny *self = (CScriptAny*)gen->GetObject();

	*self = *other;

	gen->SetReturnObject(self);
}

static void ScriptAny_Store_Generic(asIScriptGeneric *gen)
{
	void *ref = (void*)gen->GetArgAddress(0);
	int refTypeId = gen->GetArgTypeId(0);
	CScriptAny *self = (CScriptAny*)gen->GetObject();

	self->Store(ref, refTypeId);
}

static void ScriptAny_StoreInt_Generic(asIScriptGeneric *gen)
{
	asINT64 *ref = (asINT64*)gen->GetArgAddress(0);
	CScriptAny *self = (CScriptAny*)gen->GetObject();

	self->Store(*ref);
}

static void ScriptAny_StoreFlt_Generic(asIScriptGeneric *gen)
{
	double *ref = (double*)gen->GetArgAddress(0);
	CScriptAny *self = (CScriptAny*)gen->GetObject();

	self->Store(*ref);
}

static void ScriptAny_Retrieve_Generic(asIScriptGeneric *gen)
{
	void *ref = (void*)gen->GetArgAddress(0);
	int refTypeId = gen->GetArgTypeId(0);
	CScriptAny *self = (CScriptAny*)gen->GetObject();

	*(bool*)gen->GetAddressOfReturnLocation() = self->Retrieve(ref, refTypeId);
}

static void ScriptAny_RetrieveInt_Generic(asIScriptGeneric *gen)
{
	asINT64 *ref = (asINT64*)gen->GetArgAddress(0);
	CScriptAny *self = (CScriptAny*)gen->GetObject();

	*(bool*)gen->GetAddressOfReturnLocation() = self->Retrieve(*ref);
}

static void ScriptAny_RetrieveFlt_Generic(asIScriptGeneric *gen)
{
	double *ref = (double*)gen->GetArgAddress(0);
	CScriptAny *self = (CScriptAny*)gen->GetObject();

	*(bool*)gen->GetAddressOfReturnLocation() = self->Retrieve(*ref);
}

static void ScriptAny_AddRef_Generic(asIScriptGeneric *gen)
{
	CScriptAny *self = (CScriptAny*)gen->GetObject();
	self->AddRef();
}

static void ScriptAny_Release_Generic(asIScriptGeneric *gen)
{
	CScriptAny *self = (CScriptAny*)gen->GetObject();
	self->Release();
}

static void ScriptAny_GetRefCount_Generic(asIScriptGeneric *gen)
{
	CScriptAny *self = (CScriptAny*)gen->GetObject();
	*(int*)gen->GetAddressOfReturnLocation() = self->GetRefCount();
}

static void ScriptAny_SetFlag_Generic(asIScriptGeneric *gen)
{
	CScriptAny *self = (CScriptAny*)gen->GetObject();
	self->SetFlag();
}

static void ScriptAny_GetFlag_Generic(asIScriptGeneric *gen)
{
	CScriptAny *self = (CScriptAny*)gen->GetObject();
	*(bool*)gen->GetAddressOfReturnLocation() = self->GetFlag();
}

static void ScriptAny_EnumReferences_Generic(asIScriptGeneric *gen)
{
	CScriptAny *self = (CScriptAny*)gen->GetObject();
	asIScriptEngine *engine = *(asIScriptEngine**)gen->GetAddressOfArg(0);
	self->EnumReferences(engine);
}

static void ScriptAny_ReleaseAllHandles_Generic(asIScriptGeneric *gen)
{
	CScriptAny *self = (CScriptAny*)gen->GetObject();
	asIScriptEngine *engine = *(asIScriptEngine**)gen->GetAddressOfArg(0);
	self->ReleaseAllHandles(engine);
}

void RegisterScriptAny(asIScriptEngine *engine)
{
	if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") )
		RegisterScriptAny_Generic(engine);
	else
		RegisterScriptAny_Native(engine);
}

void RegisterScriptAny_Native(asIScriptEngine *engine)
{
	int r;
	r = engine->RegisterObjectType("any", sizeof(CScriptAny), asOBJ_REF | asOBJ_GC); assert( r >= 0 );

	// We'll use the generic interface for the constructor as we need the engine pointer
	r = engine->RegisterObjectBehaviour("any", asBEHAVE_FACTORY, "any@ f()", asFUNCTION(ScriptAnyFactory_Generic), asCALL_GENERIC); assert( r >= 0 );
	r = engine->RegisterObjectBehaviour("any", asBEHAVE_FACTORY, "any@ f(?&in) explicit", asFUNCTION(ScriptAnyFactory2_Generic), asCALL_GENERIC); assert( r >= 0 );
	r = engine->RegisterObjectBehaviour("any", asBEHAVE_FACTORY, "any@ f(const int64&in) explicit", asFUNCTION(ScriptAnyFactory2_Generic), asCALL_GENERIC); assert(r >= 0);
	r = engine->RegisterObjectBehaviour("any", asBEHAVE_FACTORY, "any@ f(const double&in) explicit", asFUNCTION(ScriptAnyFactory2_Generic), asCALL_GENERIC); assert(r >= 0);

	r = engine->RegisterObjectBehaviour("any", asBEHAVE_ADDREF, "void f()", asMETHOD(CScriptAny,AddRef), asCALL_THISCALL); assert( r >= 0 );
	r = engine->RegisterObjectBehaviour("any", asBEHAVE_RELEASE, "void f()", asMETHOD(CScriptAny,Release), asCALL_THISCALL); assert( r >= 0 );
	r = engine->RegisterObjectMethod("any", "any &opAssign(any&in)", asFUNCTION(ScriptAnyAssignment), asCALL_CDECL_OBJLAST); assert( r >= 0 );
	r = engine->RegisterObjectMethod("any", "void store(?&in)", asMETHODPR(CScriptAny,Store,(void*,int),void), asCALL_THISCALL); assert( r >= 0 );
	r = engine->RegisterObjectMethod("any", "void store(const int64&in)", asMETHODPR(CScriptAny,Store,(asINT64&),void), asCALL_THISCALL); assert( r >= 0 );
	r = engine->RegisterObjectMethod("any", "void store(const double&in)", asMETHODPR(CScriptAny,Store,(double&),void), asCALL_THISCALL); assert( r >= 0 );
	r = engine->RegisterObjectMethod("any", "bool retrieve(?&out) const", asMETHODPR(CScriptAny,Retrieve,(void*,int) const,bool), asCALL_THISCALL); assert( r >= 0 );
	r = engine->RegisterObjectMethod("any", "bool retrieve(int64&out) const", asMETHODPR(CScriptAny,Retrieve,(asINT64&) const,bool), asCALL_THISCALL); assert( r >= 0 );
	r = engine->RegisterObjectMethod("any", "bool retrieve(double&out) const", asMETHODPR(CScriptAny,Retrieve,(double&) const,bool), asCALL_THISCALL); assert( r >= 0 );

	// Register GC behaviours
	r = engine->RegisterObjectBehaviour("any", asBEHAVE_GETREFCOUNT, "int f()", asMETHOD(CScriptAny,GetRefCount), asCALL_THISCALL); assert( r >= 0 );
	r = engine->RegisterObjectBehaviour("any", asBEHAVE_SETGCFLAG, "void f()", asMETHOD(CScriptAny,SetFlag), asCALL_THISCALL); assert( r >= 0 );
	r = engine->RegisterObjectBehaviour("any", asBEHAVE_GETGCFLAG, "bool f()", asMETHOD(CScriptAny,GetFlag), asCALL_THISCALL); assert( r >= 0 );
	r = engine->RegisterObjectBehaviour("any", asBEHAVE_ENUMREFS, "void f(int&in)", asMETHOD(CScriptAny,EnumReferences), asCALL_THISCALL); assert( r >= 0 );
	r = engine->RegisterObjectBehaviour("any", asBEHAVE_RELEASEREFS, "void f(int&in)", asMETHOD(CScriptAny,ReleaseAllHandles), asCALL_THISCALL); assert( r >= 0 );
}

void RegisterScriptAny_Generic(asIScriptEngine *engine)
{
	int r;
	r = engine->RegisterObjectType("any", sizeof(CScriptAny), asOBJ_REF | asOBJ_GC); assert( r >= 0 );

	// We'll use the generic interface for the constructor as we need the engine pointer
	r = engine->RegisterObjectBehaviour("any", asBEHAVE_FACTORY, "any@ f()", asFUNCTION(ScriptAnyFactory_Generic), asCALL_GENERIC); assert( r >= 0 );
	r = engine->RegisterObjectBehaviour("any", asBEHAVE_FACTORY, "any@ f(?&in) explicit", asFUNCTION(ScriptAnyFactory2_Generic), asCALL_GENERIC); assert( r >= 0 );
	r = engine->RegisterObjectBehaviour("any", asBEHAVE_FACTORY, "any@ f(const int64&in) explicit", asFUNCTION(ScriptAnyFactory2_Generic), asCALL_GENERIC); assert(r >= 0);
	r = engine->RegisterObjectBehaviour("any", asBEHAVE_FACTORY, "any@ f(const double&in) explicit", asFUNCTION(ScriptAnyFactory2_Generic), asCALL_GENERIC); assert(r >= 0);

	r = engine->RegisterObjectBehaviour("any", asBEHAVE_ADDREF, "void f()", asFUNCTION(ScriptAny_AddRef_Generic), asCALL_GENERIC); assert( r >= 0 );
	r = engine->RegisterObjectBehaviour("any", asBEHAVE_RELEASE, "void f()", asFUNCTION(ScriptAny_Release_Generic), asCALL_GENERIC); assert( r >= 0 );
	r = engine->RegisterObjectMethod("any", "any &opAssign(any&in)", asFUNCTION(ScriptAnyAssignment_Generic), asCALL_GENERIC); assert( r >= 0 );
	r = engine->RegisterObjectMethod("any", "void store(?&in)", asFUNCTION(ScriptAny_Store_Generic), asCALL_GENERIC); assert( r >= 0 );
	r = engine->RegisterObjectMethod("any", "void store(const int64&in)", asFUNCTION(ScriptAny_StoreInt_Generic), asCALL_GENERIC); assert( r >= 0 );
	r = engine->RegisterObjectMethod("any", "void store(const double&in)", asFUNCTION(ScriptAny_StoreFlt_Generic), asCALL_GENERIC); assert( r >= 0 );
	r = engine->RegisterObjectMethod("any", "bool retrieve(?&out) const", asFUNCTION(ScriptAny_Retrieve_Generic), asCALL_GENERIC); assert( r >= 0 );
	r = engine->RegisterObjectMethod("any", "bool retrieve(int64&out) const", asFUNCTION(ScriptAny_RetrieveInt_Generic), asCALL_GENERIC); assert( r >= 0 );
	r = engine->RegisterObjectMethod("any", "bool retrieve(double&out) const", asFUNCTION(ScriptAny_RetrieveFlt_Generic), asCALL_GENERIC); assert( r >= 0 );

	// Register GC behaviours
	r = engine->RegisterObjectBehaviour("any", asBEHAVE_GETREFCOUNT, "int f()", asFUNCTION(ScriptAny_GetRefCount_Generic), asCALL_GENERIC); assert( r >= 0 );
	r = engine->RegisterObjectBehaviour("any", asBEHAVE_SETGCFLAG, "void f()", asFUNCTION(ScriptAny_SetFlag_Generic), asCALL_GENERIC); assert( r >= 0 );
	r = engine->RegisterObjectBehaviour("any", asBEHAVE_GETGCFLAG, "bool f()", asFUNCTION(ScriptAny_GetFlag_Generic), asCALL_GENERIC); assert( r >= 0 );
	r = engine->RegisterObjectBehaviour("any", asBEHAVE_ENUMREFS, "void f(int&in)", asFUNCTION(ScriptAny_EnumReferences_Generic), asCALL_GENERIC); assert( r >= 0 );
	r = engine->RegisterObjectBehaviour("any", asBEHAVE_RELEASEREFS, "void f(int&in)", asFUNCTION(ScriptAny_ReleaseAllHandles_Generic), asCALL_GENERIC); assert( r >= 0 );
}

CScriptAny &CScriptAny::operator=(const CScriptAny &other)
{
	// Hold on to the object type reference so it isn't destroyed too early
	if( (other.value.typeId & asTYPEID_MASK_OBJECT) )
	{
		asITypeInfo *ti = engine->GetTypeInfoById(other.value.typeId);
		if( ti )
			ti->AddRef();
	}

	FreeObject();

	value.typeId = other.value.typeId;
	if( value.typeId & asTYPEID_OBJHANDLE )
	{
		// For handles, copy the pointer and increment the reference count
		value.valueObj = other.value.valueObj;
		engine->AddRefScriptObject(value.valueObj, engine->GetTypeInfoById(value.typeId));
	}
	else if( value.typeId & asTYPEID_MASK_OBJECT )
	{
		// Create a copy of the object
		value.valueObj = engine->CreateScriptObjectCopy(other.value.valueObj, engine->GetTypeInfoById(value.typeId));
	}
	else
	{
		// Primitives can be copied directly
		value.valueInt = other.value.valueInt;
	}

	return *this;
}

int CScriptAny::CopyFrom(const CScriptAny *other)
{
	if( other == 0 ) return asINVALID_ARG;

	*this = *other;

	return 0;
}

CScriptAny::CScriptAny(asIScriptEngine *engine)
{
	this->engine = engine;
	refCount = 1;
	gcFlag = false;

	value.typeId = 0;
	value.valueInt = 0;

	// Notify the garbage collector of this object
	engine->NotifyGarbageCollectorOfNewObject(this, engine->GetTypeInfoByName("any"));
}

CScriptAny::CScriptAny(void *ref, int refTypeId, asIScriptEngine *engine)
{
	this->engine = engine;
	refCount = 1;
	gcFlag = false;

	value.typeId = 0;
	value.valueInt = 0;

	// Notify the garbage collector of this object
	engine->NotifyGarbageCollectorOfNewObject(this, engine->GetTypeInfoByName("any"));

	Store(ref, refTypeId);
}

CScriptAny::~CScriptAny()
{
	FreeObject();
}

void CScriptAny::Store(void *ref, int refTypeId)
{
	// This method is not expected to be used for primitive types, except for bool, int64, or double
	assert( refTypeId > asTYPEID_DOUBLE || refTypeId == asTYPEID_VOID || refTypeId == asTYPEID_BOOL || refTypeId == asTYPEID_INT64 || refTypeId == asTYPEID_DOUBLE );

	// Hold on to the object type reference so it isn't destroyed too early
	if( (refTypeId & asTYPEID_MASK_OBJECT) )
	{
		asITypeInfo *ti = engine->GetTypeInfoById(refTypeId);
		if( ti )
			ti->AddRef();
	}

	FreeObject();

	value.typeId = refTypeId;
	if( value.typeId & asTYPEID_OBJHANDLE )
	{
		// We're receiving a reference to the handle, so we need to dereference it
		value.valueObj = *(void**)ref;
		engine->AddRefScriptObject(value.valueObj, engine->GetTypeInfoById(value.typeId));
	}
	else if( value.typeId & asTYPEID_MASK_OBJECT )
	{
		// Create a copy of the object
		value.valueObj = engine->CreateScriptObjectCopy(ref, engine->GetTypeInfoById(value.typeId));
	}
	else
	{
		// Primitives can be copied directly
		value.valueInt = 0;

		// Copy the primitive value
		// We receive a pointer to the value.
		int size = engine->GetSizeOfPrimitiveType(value.typeId);
		memcpy(&value.valueInt, ref, size);
	}
}

void CScriptAny::Store(double &ref)
{
	Store(&ref, asTYPEID_DOUBLE);
}

void CScriptAny::Store(asINT64 &ref)
{
	Store(&ref, asTYPEID_INT64);
}

bool CScriptAny::Retrieve(void *ref, int refTypeId) const
{
	// This method is not expected to be used for primitive types, except for bool, int64, or double
	assert( refTypeId > asTYPEID_DOUBLE || refTypeId == asTYPEID_BOOL || refTypeId == asTYPEID_INT64 || refTypeId == asTYPEID_DOUBLE );

	if( refTypeId & asTYPEID_OBJHANDLE )
	{
		// Is the handle type compatible with the stored value?

		// A handle can be retrieved if the stored type is a handle of same or compatible type
		// or if the stored type is an object that implements the interface that the handle refer to.
		if( (value.typeId & asTYPEID_MASK_OBJECT) )
		{
			// Don't allow the retrieval if the stored handle is to a const object but not the wanted handle
			if( (value.typeId & asTYPEID_HANDLETOCONST) && !(refTypeId & asTYPEID_HANDLETOCONST) )
				return false;

			// RefCastObject will increment the refCount of the returned pointer if successful
			engine->RefCastObject(value.valueObj, engine->GetTypeInfoById(value.typeId), engine->GetTypeInfoById(refTypeId), reinterpret_cast<void**>(ref));
			if( *(asPWORD*)ref == 0 )
				return false;
			return true;
		}
	}
	else if( refTypeId & asTYPEID_MASK_OBJECT )
	{
		// Is the object type compatible with the stored value?

		// Copy the object into the given reference
		if( value.typeId == refTypeId )
		{
			engine->AssignScriptObject(ref, value.valueObj, engine->GetTypeInfoById(value.typeId));
			return true;
		}
	}
	else
	{
		// Is the primitive type compatible with the stored value?

		if( value.typeId == refTypeId )
		{
			int size = engine->GetSizeOfPrimitiveType(refTypeId);
			memcpy(ref, &value.valueInt, size);
			return true;
		}

		// We know all numbers are stored as either int64 or double, since we register overloaded functions for those
		if( value.typeId == asTYPEID_INT64 && refTypeId == asTYPEID_DOUBLE )
		{
			*(double*)ref = double(value.valueInt);
			return true;
		}
		else if( value.typeId == asTYPEID_DOUBLE && refTypeId == asTYPEID_INT64 )
		{
			*(asINT64*)ref = asINT64(value.valueFlt);
			return true;
		}
	}

	return false;
}

bool CScriptAny::Retrieve(asINT64 &outValue) const
{
	return Retrieve(&outValue, asTYPEID_INT64);
}

bool CScriptAny::Retrieve(double &outValue) const
{
	return Retrieve(&outValue, asTYPEID_DOUBLE);
}

int CScriptAny::GetTypeId() const
{
	return value.typeId;
}

void CScriptAny::FreeObject()
{
	// If it is a handle or a ref counted object, call release
	if( value.typeId & asTYPEID_MASK_OBJECT )
	{
		// Let the engine release the object
		asITypeInfo *ti = engine->GetTypeInfoById(value.typeId);
		engine->ReleaseScriptObject(value.valueObj, ti);

		// Release the object type info
		if( ti )
			ti->Release();

		value.valueObj = 0;
		value.typeId = 0;
	}

	// For primitives, there's nothing to do
}

void CScriptAny::EnumReferences(asIScriptEngine *inEngine)
{
	// If we're holding a reference, we'll notify the garbage collector of it
	if (value.valueObj && (value.typeId & asTYPEID_MASK_OBJECT))
	{
		asITypeInfo *subType = engine->GetTypeInfoById(value.typeId);
		if ((subType->GetFlags() & asOBJ_REF))
		{
			inEngine->GCEnumCallback(value.valueObj);
		}
		else if ((subType->GetFlags() & asOBJ_VALUE) && (subType->GetFlags() & asOBJ_GC))
		{
			// For value types we need to forward the enum callback
			// to the object so it can decide what to do
			engine->ForwardGCEnumReferences(value.valueObj, subType);
		}

		// The object type itself is also garbage collected
		asITypeInfo *ti = inEngine->GetTypeInfoById(value.typeId);
		if (ti)
			inEngine->GCEnumCallback(ti);
	}
}

void CScriptAny::ReleaseAllHandles(asIScriptEngine * /*engine*/)
{
	FreeObject();
}

int CScriptAny::AddRef() const
{
	// Increase counter and clear flag set by GC
	gcFlag = false;
	return asAtomicInc(refCount);
}

int CScriptAny::Release() const
{
	// Decrease the ref counter
	gcFlag = false;
	if( asAtomicDec(refCount) == 0 )
	{
		// Delete this object as no more references to it exists
		delete this;
		return 0;
	}

	return refCount;
}

int CScriptAny::GetRefCount()
{
	return refCount;
}

void CScriptAny::SetFlag()
{
	gcFlag = true;
}

bool CScriptAny::GetFlag()
{
	return gcFlag;
}

END_AS_NAMESPACE


code:
#ifndef SCRIPTANY_H
#define SCRIPTANY_H

#ifndef ANGELSCRIPT_H
// Avoid having to inform include path if header is already include before
#include <angelscript.h>
#endif

BEGIN_AS_NAMESPACE

class CScriptAny
{
public:
	// Constructors
	CScriptAny(asIScriptEngine *engine);
	CScriptAny(void *ref, int refTypeId, asIScriptEngine *engine);

	// Memory management
	int AddRef() const;
	int Release() const;

	// Copy the stored value from another any object
	CScriptAny &operator=(const CScriptAny&);
	int CopyFrom(const CScriptAny *other);

	// Store the value, either as variable type, integer number, or real number
	void Store(void *ref, int refTypeId);
	void Store(asINT64 &value);
	void Store(double &value);

	// Retrieve the stored value, either as variable type, integer number, or real number
	bool Retrieve(void *ref, int refTypeId) const;
	bool Retrieve(asINT64 &value) const;
	bool Retrieve(double &value) const;

	// Get the type id of the stored value
	int  GetTypeId() const;

	// GC methods
	int  GetRefCount();
	void SetFlag();
	bool GetFlag();
	void EnumReferences(asIScriptEngine *engine);
	void ReleaseAllHandles(asIScriptEngine *engine);

protected:
	virtual ~CScriptAny();
	void FreeObject();

	mutable int refCount;
	mutable bool gcFlag;
	asIScriptEngine *engine;

	// The structure for holding the values
    struct valueStruct
    {
        union
        {
            asINT64 valueInt;
            double  valueFlt;
            void   *valueObj;
        };
        int   typeId;
    };

	valueStruct value;
};

void RegisterScriptAny(asIScriptEngine *engine);
void RegisterScriptAny_Native(asIScriptEngine *engine);
void RegisterScriptAny_Generic(asIScriptEngine *engine);

END_AS_NAMESPACE

#endif