/*************************************************************************
 *                                                                       *
 * ODER's Utilities Library. Copyright (C) 2008 Oleh Derevenko.          *
 * All rights reserved.  e-mail: odar@eleks.com (change all "a" to "e")  *
 *                                                                       *
 * This library is free software; you can redistribute it and/or         *
 * modify it under the terms of EITHER:                                  *
 *   (1) The GNU Lesser General Public License as published by the Free  *
 *       Software Foundation; either version 3 of the License, or (at    *
 *       your option) any later version. The text of the GNU Lesser      *
 *       General Public License is included with this library in the     *
 *       file LICENSE-LESSER.TXT. Since LGPL is the extension of GPL     *
 *       the text of GNU General Public License is also provided for     *
 *       your information in file LICENSE.TXT.                           *
 *   (2) The BSD-style license that is included with this library in     *
 *       the file LICENSE-BSD.TXT.                                       *
 *   (3) The zlib/libpng license that is included with this library in   *
 *       the file LICENSE-ZLIB.TXT                                       *
 *                                                                       *
 * This library is distributed WITHOUT ANY WARRANTY, including implied   *
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.      *
 * See the files LICENSE.TXT and LICENSE-LESSER.TXT or LICENSE-BSD.TXT   *
 * or LICENSE-ZLIB.TXT for more details.                                 *
 *                                                                       *
 *************************************************************************/

#include <ou/platform.h>

#if _OU_COMPILER == _OU_COMPILER_MSVC

#pragma warning(disable:4786)


#endif

#include <ou/threadlocalstorage.h>
#include <ou/atomic.h>
#include <ou/atomicflags.h>
#include <ou/simpleflags.h>
#include <ou/flagsdefines.h>
#include <ou/enumarrays.h>
#include <ou/templates.h>
#include <ou/typewrapper.h>
#include <ou/customization.h>
#include <ou/inttypes.h>
#include <ou/macros.h>
#include <ou/malloc.h>

#include <ou/namespace.h>
using namespace _OU_NAMESPACE;

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


//////////////////////////////////////////////////////////////////////////

typedef bool (*CFeatureTestProcedure)();


bool TestSubsystem(unsigned int &nOutSuccessCount, unsigned int &nOutTestCount,
	const unsigned int uiFeatureMax, const char *const *aszFeatureNames, CFeatureTestProcedure const *afnFeatureTests)
{
	unsigned int nSuccessCount = 0;
	
	for (unsigned int uiSubsystemFeature = 0; uiSubsystemFeature != uiFeatureMax; ++uiSubsystemFeature)
	{
		const char *szFeatureName = aszFeatureNames[uiSubsystemFeature];
		printf("Testing %34s: ", szFeatureName);
		
		CFeatureTestProcedure fnTestProcedure = afnFeatureTests[uiSubsystemFeature];
		bool bTestResult = fnTestProcedure();
		printf("%s\n", bTestResult ? "success" : "*** failure ***");
		
		if (bTestResult)
		{
			nSuccessCount += 1;
		}
	}
	
	nOutSuccessCount = nSuccessCount;
	nOutTestCount = uiFeatureMax;
	return nSuccessCount == uiFeatureMax;
}



//////////////////////////////////////////////////////////////////////////

bool g_bTestTLSAPIInitialized = false;
HTLSKEY g_htkTestTLSKey;

enum ETESTTLSVALUES
{
	TTV_FIRSTVALUE,
	TTV_SECONDVALUE,

	TTV__MAX,
};

unsigned int g_uiTestTLSDestructorCallCount = 0;
unsigned int g_uiTestTLSDestructorSuccessCount = 0;

void _OU_CONVENTION_CALLBACK TestTlsSecondValueDestructor(void *pv_Value)
{
	g_uiTestTLSDestructorCallCount += 1;

	if (pv_Value == (void *)(&TestTlsSecondValueDestructor))
	{
		g_uiTestTLSDestructorSuccessCount += 1;
	}
}


bool TestTls_Initialization()
{
	bool bResult = false;
	
	do
	{
		if (!CTLSInitialization::InitializeTLSAPI(g_htkTestTLSKey, 1, 0))
		{
			break;
		}

		CTLSInitialization::FinalizeTLSAPI();

		if (!CTLSInitialization::InitializeTLSAPI(g_htkTestTLSKey, TTV__MAX, CTLSInitialization::SIF_MANUAL_CLEANUP_ON_THREAD_EXIT))
		{
			break;
		}

		g_bTestTLSAPIInitialized = true;
	
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestTls_GetSetValue()
{
	bool bResult = false;
	
	do
	{
		tlsvaluetype vtFirstValue = CThreadLocalStorage::GetStorageValue(g_htkTestTLSKey, TTV_FIRSTVALUE);

		if (vtFirstValue != 0)
		{
			break;
		}
	
		tlsvaluetype vtSecondValue = CThreadLocalStorage::GetStorageValue(g_htkTestTLSKey, TTV_SECONDVALUE);
		
		if (vtSecondValue != 0)
		{
			break;
		}

		if (!CThreadLocalStorage::SetStorageValue(g_htkTestTLSKey, TTV_FIRSTVALUE, (tlsvaluetype)&TestTls_GetSetValue))
		{
			break;
		}
		
		if (!CThreadLocalStorage::SetStorageValue(g_htkTestTLSKey, TTV_SECONDVALUE, (tlsvaluetype)&TestTlsSecondValueDestructor, &TestTlsSecondValueDestructor))
		{
			break;
		}

		vtFirstValue = CThreadLocalStorage::GetStorageValue(g_htkTestTLSKey, TTV_FIRSTVALUE);

		if ((void *)vtFirstValue != &TestTls_GetSetValue)
		{
			break;
		}

		vtSecondValue = CThreadLocalStorage::GetStorageValue(g_htkTestTLSKey, TTV_SECONDVALUE);

		if ((void *)vtSecondValue != &TestTlsSecondValueDestructor)
		{
			break;
		}
		
		if (!CThreadLocalStorage::SetStorageValue(g_htkTestTLSKey, TTV_SECONDVALUE, 0, &TestTlsSecondValueDestructor))
		{
			break;
		}

		vtSecondValue = CThreadLocalStorage::GetStorageValue(g_htkTestTLSKey, TTV_SECONDVALUE);
		
		if (vtSecondValue != 0)
		{
			break;
		}
		
		if (!CThreadLocalStorage::SetStorageValue(g_htkTestTLSKey, TTV_SECONDVALUE, (tlsvaluetype)&TestTlsSecondValueDestructor, &TestTlsSecondValueDestructor))
		{
			break;
		}
		
		if (g_uiTestTLSDestructorCallCount != 0)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestTls_UnsafeGetSetValue()
{
	bool bResult = false;
	
	do
	{
		tlsvaluetype vtFirstValue = CThreadLocalStorage::UnsafeGetStorageValue(g_htkTestTLSKey, TTV_FIRSTVALUE);
		
		if ((void *)vtFirstValue != &TestTls_GetSetValue)
		{
			break;
		}
		
		tlsvaluetype vtSecondValue = CThreadLocalStorage::UnsafeGetStorageValue(g_htkTestTLSKey, TTV_SECONDVALUE);
		
		if ((void *)vtSecondValue != &TestTlsSecondValueDestructor)
		{
			break;
		}

		CThreadLocalStorage::UnsafeSetStorageValue(g_htkTestTLSKey, TTV_FIRSTVALUE, (tlsvaluetype)(size_t)(-1));
		CThreadLocalStorage::UnsafeSetStorageValue(g_htkTestTLSKey, TTV_SECONDVALUE, (tlsvaluetype)(size_t)(-1));

		vtFirstValue = CThreadLocalStorage::UnsafeGetStorageValue(g_htkTestTLSKey, TTV_FIRSTVALUE);
		
		if ((size_t)vtFirstValue != (size_t)(-1))
		{
			break;
		}
		
		vtSecondValue = CThreadLocalStorage::UnsafeGetStorageValue(g_htkTestTLSKey, TTV_SECONDVALUE);
		
		if ((size_t)vtSecondValue != (size_t)(-1))
		{
			break;
		}
		
		// Safe function used by intent !!!
		vtFirstValue = CThreadLocalStorage::GetStorageValue(g_htkTestTLSKey, TTV_FIRSTVALUE);
		
		if ((size_t)vtFirstValue != (size_t)(-1))
		{
			break;
		}
		
		// Safe function used by intent !!!
		vtSecondValue = CThreadLocalStorage::GetStorageValue(g_htkTestTLSKey, TTV_SECONDVALUE);
		
		if ((size_t)vtSecondValue != (size_t)(-1))
		{
			break;
		}
	
		CThreadLocalStorage::UnsafeSetStorageValue(g_htkTestTLSKey, TTV_SECONDVALUE, (tlsvaluetype)(&TestTlsSecondValueDestructor));

		if (g_uiTestTLSDestructorCallCount != 0)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestTls_CleanupDestructor()
{
	bool bResult = false;
	
	do
	{
		CTLSInitialization::CleanupOnThreadExit();

		if (g_uiTestTLSDestructorCallCount != 1 || g_uiTestTLSDestructorSuccessCount != 1)
		{
			break;
		}
		
		tlsvaluetype vtFirstValue = CThreadLocalStorage::GetStorageValue(g_htkTestTLSKey, TTV_FIRSTVALUE);
		
		if (vtFirstValue != 0)
		{
			break;
		}
		
		// Safe function used by intent !!!
		tlsvaluetype vtSecondValue = CThreadLocalStorage::GetStorageValue(g_htkTestTLSKey, TTV_SECONDVALUE);
		
		if (vtSecondValue != 0)
		{
			break;
		}

		g_uiTestTLSDestructorCallCount = 0;
		g_uiTestTLSDestructorSuccessCount = 0;

		CTLSInitialization::CleanupOnThreadExit();
		
		if (g_uiTestTLSDestructorCallCount != 0)
		{
			break;
		}
		
		if (!CThreadLocalStorage::SetStorageValue(g_htkTestTLSKey, TTV_SECONDVALUE, 0, &TestTlsSecondValueDestructor))
		{
			break;
		}
	
		CTLSInitialization::CleanupOnThreadExit();
		
		if (g_uiTestTLSDestructorCallCount != 0)
		{
			break;
		}
		
		if (!CThreadLocalStorage::SetStorageValue(g_htkTestTLSKey, TTV_SECONDVALUE, (tlsvaluetype)(size_t)(-1), &TestTlsSecondValueDestructor))
		{
			break;
		}
		
		if (g_uiTestTLSDestructorCallCount != 0)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestTls_Finalization()
{
	OU_ASSERT(g_bTestTLSAPIInitialized);

	bool bResult = false;
	
	do
	{
		CTLSInitialization::FinalizeTLSAPI();
		
		g_bTestTLSAPIInitialized = false;

		if (g_uiTestTLSDestructorCallCount != 1 || g_uiTestTLSDestructorSuccessCount != 0)
		{
			break;
		}
	
		bResult = true;
	}
	while (false);
	
	return bResult;
}


enum EOUTLSFEATURE
{
	OHF__MIN,
	
	OHF_INITIALIZATION = OHF__MIN,
	OHF_GETSETVALUE,
	OHF_UNSAFEGETSETVALUE,
	OHF_CLEANUPDESTRUCTOR,
	OHF_FINALIZATION,
	
	OHF__MAX,
};

template<>
CFeatureTestProcedure const CEnumUnsortedElementArray<EOUTLSFEATURE, OHF__MAX, CFeatureTestProcedure>::m_aetElementArray[] =
{
	&TestTls_Initialization, // OHF_INITIALIZATION
	&TestTls_GetSetValue, // OHF_GETSETVALUE,
	&TestTls_UnsafeGetSetValue, // OHF_UNSAFEGETSETVALUE,
	&TestTls_CleanupDestructor, // OHF_CLEANUPDESTRUCTOR,
	&TestTls_Finalization, // OHF_FINALIZATION,
};
static const CEnumUnsortedElementArray<EOUTLSFEATURE, OHF__MAX, CFeatureTestProcedure> g_afnTlsFeatureTestProcedures;

template<>
const char *const CEnumUnsortedElementArray<EOUTLSFEATURE, OHF__MAX, const char *>::m_aetElementArray[] =
{
	"API Initialization", // OHF_INITIALIZATION
	"Get.../SetStorageValue", // OHF_GETSETVALUE,
	"UnsafeGet.../UnsafeSetStorageValue", // OHF_UNSAFEGETSETVALUE,
	"Storage Cleanup/Value Destructors", // OHF_CLEANUPDESTRUCTOR,
	"API Finalization", // OHF_FINALIZATION,
};
static const CEnumUnsortedElementArray<EOUTLSFEATURE, OHF__MAX, const char *> g_aszTlsFeatureTestNames;


bool TestTLS(unsigned int &nOutSuccessCount, unsigned int &nOutTestCount)
{
	bool bResult = TestSubsystem(nOutSuccessCount, nOutTestCount, OHF__MAX, g_aszTlsFeatureTestNames.GetStoragePointer(), g_afnTlsFeatureTestProcedures.GetStoragePointer());

	if (g_bTestTLSAPIInitialized)
	{
		CTLSInitialization::FinalizeTLSAPI();
	}
	
	return bResult;
}


//////////////////////////////////////////////////////////////////////////

bool TestAtomic_Increment()
{
	bool bResult = false;
	
	do
	{
		volatile atomicord32 aoStorage = (atomicord32)(-1);

		// Putting function inside of conditional operator causes
		// incorrect code generation by GCC 4.0.1 on MacOS X Leopard 64 bit.
		atomicord32 aoIncrementFirstResult = AtomicIncrement(&aoStorage);
		if (aoIncrementFirstResult != 0 || aoStorage != (atomicord32)0)
		{
			break;
		}
		
		if (AtomicIncrement(&aoStorage) != (atomicord32)1 || aoStorage != (atomicord32)1)
		{
			break;
		}
	
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestAtomic_Decrement()
{
	bool bResult = false;
	
	do
	{
		volatile atomicord32 aoStorage = (atomicord32)1;
		
		// Putting function inside of conditional operator causes
		// incorrect code generation by GCC 4.0.1 on MacOS X Leopard 64 bit.
		atomicord32 aoDecrementFirstResult = AtomicDecrement(&aoStorage);
		if (aoDecrementFirstResult != (atomicord32)0 || aoStorage != (atomicord32)0)
		{
			break;
		}
		
		if (AtomicDecrement(&aoStorage) != (atomicord32)(-1) || aoStorage != (atomicord32)(-1))
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestAtomic_IncrementNoResult()
{
	bool bResult = false;
	
	do
	{
		volatile atomicord32 aoStorage = (atomicord32)(-1);
		
		AtomicIncrementNoResult(&aoStorage);

		if (aoStorage != (atomicord32)0)
		{
			break;
		}
		
		AtomicIncrementNoResult(&aoStorage);

		if (aoStorage != (atomicord32)1)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestAtomic_DecrementNoResult()
{
	bool bResult = false;
	
	do
	{
		volatile atomicord32 aoStorage = (atomicord32)1;
		
		AtomicDecrementNoResult(&aoStorage);

		if (aoStorage != (atomicord32)0)
		{
			break;
		}
		
		AtomicDecrementNoResult(&aoStorage);

		if (aoStorage != (atomicord32)(-1))
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestAtomic_Exchange()
{
	bool bResult = false;
	
	do
	{
		volatile atomicord32 aoStorage = 0;

		if (AtomicExchange(&aoStorage, (atomicord32)1) != 0 || aoStorage != (atomicord32)1)
		{
			break;
		}
		
		if (AtomicExchange(&aoStorage, (atomicord32)(-1)) != (atomicord32)1 || aoStorage != (atomicord32)(-1))
		{
			break;
		}
		
		if (AtomicExchange(&aoStorage, 0) != (atomicord32)(-1) || aoStorage != 0)
		{
			break;
		}
		
		if (AtomicExchange(&aoStorage, 0) != 0 || aoStorage != 0)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;

}

bool TestAtomic_ExchangeAdd()
{
	bool bResult = false;
	
	do
	{
		volatile atomicord32 aoStorage = 0;

		if (AtomicExchangeAdd(&aoStorage, (atomicord32)1) != 0 || aoStorage != (atomicord32)1)
		{
			break;
		}
		
		if (AtomicExchangeAdd(&aoStorage, (atomicord32)(-2)) != 1 || aoStorage != (atomicord32)(-1))
		{
			break;
		}
		
		if (AtomicExchangeAdd(&aoStorage, (atomicord32)1) != (atomicord32)(-1) || aoStorage != 0)
		{
			break;
		}
	
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestAtomic_ExchangeAddNoResult()
{
	bool bResult = false;
	
	do
	{
		volatile atomicord32 aoStorage = 0;
		
		AtomicExchangeAddNoResult(&aoStorage, (atomicord32)1);
		
		if (aoStorage != (atomicord32)1)
		{
			break;
		}
		
		AtomicExchangeAddNoResult(&aoStorage, (atomicord32)(-2));

		if (aoStorage != (atomicord32)(-1))
		{
			break;
		}
		
		AtomicExchangeAddNoResult(&aoStorage, (atomicord32)1);
		
		if (aoStorage != 0)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestAtomic_CompareExchange()
{
	bool bResult = false;
	
	do
	{
		volatile atomicord32 aoStorage = 0;

		if (AtomicCompareExchange(&aoStorage, 1, 1) || aoStorage != 0)
		{
			break;
		}
		
		if (!AtomicCompareExchange(&aoStorage, 0, 1) || aoStorage != 1)
		{
			break;
		}
		
		if (!AtomicCompareExchange(&aoStorage, 1, 1) || aoStorage != 1)
		{
			break;
		}
		
		if (!AtomicCompareExchange(&aoStorage, 1, (atomicord32)(-1)) || aoStorage != (atomicord32)(-1))
		{
			break;
		}
		
		if (AtomicCompareExchange(&aoStorage, 1, (atomicord32)(-1)) || aoStorage != (atomicord32)(-1))
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

const atomicord32 g_aoBitmask = (atomicord32)(OU_INT32_MIN + 1);

bool TestAtomic_And()
{
	bool bResult = false;
	
	do
	{
		volatile atomicord32 aoStorage = (atomicord32)OU_UINT32_MAX;

		if (AtomicAnd(&aoStorage, g_aoBitmask) != (atomicord32)OU_UINT32_MAX || aoStorage != g_aoBitmask)
		{
			break;
		}

		if (AtomicAnd(&aoStorage, 0) != g_aoBitmask || aoStorage != 0)
		{
			break;
		}
	
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestAtomic_Or()
{
	bool bResult = false;
	
	do
	{
		volatile atomicord32 aoStorage = 0;
		
		if (AtomicOr(&aoStorage, g_aoBitmask) != 0 || aoStorage != g_aoBitmask)
		{
			break;
		}
		
		if (AtomicOr(&aoStorage, (atomicord32)OU_UINT32_MAX) != g_aoBitmask || aoStorage != (atomicord32)OU_UINT32_MAX)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestAtomic_Xor()
{
	bool bResult = false;
	
	do
	{
		volatile atomicord32 aoStorage = 0;
		
		if (AtomicXor(&aoStorage, g_aoBitmask) != 0 || aoStorage != g_aoBitmask)
		{
			break;
		}
		
		if (AtomicXor(&aoStorage, (atomicord32)OU_UINT32_MAX) != g_aoBitmask || aoStorage != (atomicord32)(OU_UINT32_MAX ^ g_aoBitmask))
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestAtomic_AndNoResult()
{
	bool bResult = false;
	
	do
	{
		volatile atomicord32 aoStorage = (atomicord32)OU_UINT32_MAX;
		
		AtomicAndNoResult(&aoStorage, g_aoBitmask);

		if (aoStorage != g_aoBitmask)
		{
			break;
		}
		
		AtomicAndNoResult(&aoStorage, 0);

		if (aoStorage != 0)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestAtomic_OrNoResult()
{
	bool bResult = false;
	
	do
	{
		volatile atomicord32 aoStorage = 0;
		
		AtomicOrNoResult(&aoStorage, g_aoBitmask);

		if (aoStorage != g_aoBitmask)
		{
			break;
		}
		
		AtomicOrNoResult(&aoStorage, (atomicord32)OU_UINT32_MAX);

		if (aoStorage != (atomicord32)OU_UINT32_MAX)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestAtomic_XorNoResult()
{
	bool bResult = false;
	
	do
	{
		volatile atomicord32 aoStorage = 0;
		
		AtomicXorNoResult(&aoStorage, g_aoBitmask);

		if (aoStorage != g_aoBitmask)
		{
			break;
		}
		
		AtomicXorNoResult(&aoStorage, (atomicord32)OU_UINT32_MAX);

		if (aoStorage != (atomicord32)(OU_UINT32_MAX ^ g_aoBitmask))
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestAtomic_ExchangePointer()
{
	bool bResult = false;
	
	do
	{
		volatile atomicptr apStorage = NULL;

		if (AtomicExchangePointer(&apStorage, (atomicptr)(&TestAtomic_ExchangePointer)) != NULL || apStorage != (atomicptr)(&TestAtomic_ExchangePointer))
		{
			break;
		}
	
		if (AtomicExchangePointer(&apStorage, (atomicptr)(&apStorage)) != (atomicptr)(&TestAtomic_ExchangePointer) || apStorage != (atomicptr)(&apStorage))
		{
			break;
		}
		
		if (AtomicExchangePointer(&apStorage, NULL) != (atomicptr)(&apStorage) || apStorage != NULL)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestAtomic_CompareExchangePointer()
{
	bool bResult = false;
	
	do
	{
		volatile atomicptr apStorage = NULL;
		
		if (AtomicCompareExchangePointer(&apStorage, (atomicptr)(&TestAtomic_CompareExchangePointer), (atomicptr)(&TestAtomic_CompareExchangePointer)) || apStorage != NULL)
		{
			break;
		}
		
		if (!AtomicCompareExchangePointer(&apStorage, NULL, (atomicptr)(&TestAtomic_CompareExchangePointer)) || apStorage != (atomicptr)(&TestAtomic_CompareExchangePointer))
		{
			break;
		}
		
		if (!AtomicCompareExchangePointer(&apStorage, (atomicptr)(&TestAtomic_CompareExchangePointer), (atomicptr)(&apStorage)) || apStorage != (atomicptr)(&apStorage))
		{
			break;
		}
		
		if (!AtomicCompareExchangePointer(&apStorage, (atomicptr)(&apStorage), (atomicptr)(&apStorage)) || apStorage != (atomicptr)(&apStorage))
		{
			break;
		}
		
		if (AtomicCompareExchangePointer(&apStorage, NULL, NULL) || apStorage != (atomicptr)(&apStorage))
		{
			break;
		}
		
		if (!AtomicCompareExchangePointer(&apStorage, (atomicptr)(&apStorage), NULL) || apStorage != NULL)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}


enum EOUATOMICFEATURE
{
	OOF__MIN,
		
	OOF_INCREMENT = OOF__MIN,
	OOF_DECREMENT,
	OOF_INCREMENTNORESULT,
	OOF_DECREMENTNORESULT,
	OOF_EXCHANGE,
	OOF_EXCHANGEADD,
	OOF_EXCHANGEADDNORESULT,
	OOF_COMPAREEXCHANGE,
	OOF_AND,
	OOF_OR,
	OOF_XOR,
	OOF_ANDNORESULT,
	OOF_ORNORESULT,
	OOF_XORNORESULT,
	OOF_EXCHANGEPOINTER,
	OOF_COMPAREEXCHANGEPOINTER,
	
	OOF__MAX,
};

template<>
CFeatureTestProcedure const CEnumUnsortedElementArray<EOUATOMICFEATURE, OOF__MAX, CFeatureTestProcedure>::m_aetElementArray[] =
{
	&TestAtomic_Increment, // OOF_INCREMENT,
	&TestAtomic_Decrement, // OOF_DECREMENT,
	&TestAtomic_IncrementNoResult, // OOF_INCREMENTNORESULT,
	&TestAtomic_DecrementNoResult, // OOF_DECREMENTNORESULT,
	&TestAtomic_Exchange, // OOF_EXCHANGE,
	&TestAtomic_ExchangeAdd, // OOF_EXCHANGEADD,
	&TestAtomic_ExchangeAddNoResult, // OOF_EXCHANGEADDNORESULT,
	&TestAtomic_CompareExchange, // OOF_COMPAREEXCHANGE,
	&TestAtomic_And, // OOF_AND,
	&TestAtomic_Or, // OOF_OR,
	&TestAtomic_Xor, // OOF_XOR,
	&TestAtomic_AndNoResult, // OOF_ANDNORESULT,
	&TestAtomic_OrNoResult, // OOF_ORNORESULT,
	&TestAtomic_XorNoResult, // OOF_XORNORESULT,
	&TestAtomic_ExchangePointer, // OOF_EXCHANGEPOINTER,
	&TestAtomic_CompareExchangePointer, // OOF_COMPAREEXCHANGEPOINTER,
};
static const CEnumUnsortedElementArray<EOUATOMICFEATURE, OOF__MAX, CFeatureTestProcedure> g_afnAtomicFeatureTestProcedures;

template<>
const char *const CEnumUnsortedElementArray<EOUATOMICFEATURE, OOF__MAX, const char *>::m_aetElementArray[] =
{
	"AtomicIncrement", // OOF_INCREMENT,
	"AtomicDecrement", // OOF_DECREMENT,
	"AtomicIncrementNoResult", // OOF_INCREMENTNORESULT,
	"AtomicDecrementNoResult", // OOF_DECREMENTNORESULT,
	"AtomicExchange", // OOF_EXCHANGE,
	"AtomicExchangeAdd", // OOF_EXCHANGEADD,
	"AtomicExchangeAddNoResult", // OOF_EXCHANGEADDNORESULT,
	"AtomicCompareExchange", // OOF_COMPAREEXCHANGE,
	"AtomicAnd", // OOF_AND,
	"AtomicOr", // OOF_OR,
	"AtomicXor", // OOF_XOR,
	"AtomicAndNoResult", // OOF_ANDNORESULT,
	"AtomicOrNoResult", // OOF_ORNORESULT,
	"AtomicXorNoResult", // OOF_XORNORESULT,
	"AtomicExchangePointer", // OOF_EXCHANGEPOINTER,
	"AtomicCompareExchangePointer", // OOF_COMPAREEXCHANGEPOINTER,
};
static const CEnumUnsortedElementArray<EOUATOMICFEATURE, OOF__MAX, const char *> g_aszAtomicFeatureTestNames;


bool TestAtomic(unsigned int &nOutSuccessCount, unsigned int &nOutTestCount)
{
	bool bResult = false;
	nOutSuccessCount = 0;
	nOutTestCount = OOF__MAX;

	bool bAPIInitialized = false;
	
	do
	{
		if (!InitializeAtomicAPI())
		{
			break;
		}
		
		bAPIInitialized = true;

		if (!TestSubsystem(nOutSuccessCount, nOutTestCount, OOF__MAX, g_aszAtomicFeatureTestNames.GetStoragePointer(), g_afnAtomicFeatureTestProcedures.GetStoragePointer()))
		{
			break;
		}

		bResult = true;
	}
	while (false);
	
	if (bAPIInitialized)
	{
		FinalizeAtomicAPI();
	}

	return bResult;
}


//////////////////////////////////////////////////////////////////////////

const atomicord32 g_aoTestValue32 = (atomicord32)0xA5A5A5A5;
const atomicord32 g_aoTestMask32 = (atomicord32)0xC6C6C6C6;
const atomicord32 g_aoTestBit32 = (atomicord32)OU_INT32_MIN;
const atomicord32 g_aoTestAnotherBit32 = (atomicord32)((uint32ou)OU_INT32_MIN >> 1);


bool TestAtomicFlags_Constructors()
{
	bool bResult = false;
	
	do
	{
		if (sizeof(CAtomicFlags::value_type) != sizeof(atomicord32))
		{
			break;
		}

		CAtomicFlags afEmptyFlags;

		if (afEmptyFlags.QueryFlagsAllValues())
		{
			break;
		}

		CAtomicFlags afFullFlags(OU_UINT32_MAX);
		
		if (afFullFlags.QueryFlagsAllValues() != (atomicord32)OU_UINT32_MAX)
		{
			break;
		}

		CAtomicFlags afCopyOfFullFlags(afFullFlags);

		if (afCopyOfFullFlags.QueryFlagsAllValues() != (atomicord32)OU_UINT32_MAX)
		{
			break;
		}
	
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestAtomicFlags_AssignFlagsAllValues()
{
	bool bResult = false;
	
	do
	{
		CAtomicFlags afTestFlags;

		afTestFlags.AssignFlagsAllValues(OU_UINT32_MAX);

		if (afTestFlags.QueryFlagsAllValues() != (atomicord32)OU_UINT32_MAX)
		{
			break;
		}

		afTestFlags.AssignFlagsAllValues(0);

		if (afTestFlags.QueryFlagsAllValues() != 0)
		{
			break;
		}
	
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestAtomicFlags_QueryFlagsAllValues()
{
	bool bResult = false;
	
	do
	{
		CAtomicFlags afTestFlags(g_aoTestValue32);
		
		if (afTestFlags.QueryFlagsAllValues() != g_aoTestValue32)
		{
			break;
		}

		// Double check to be sure ;-)
		if (afTestFlags.QueryFlagsAllValues() != g_aoTestValue32)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestAtomicFlags_SetFlagsMaskValue()
{
	bool bResult = false;
	
	do
	{
		CAtomicFlags afTestFlags(g_aoTestValue32);

		afTestFlags.SetFlagsMaskValue(g_aoTestMask32, true);

		if (afTestFlags.QueryFlagsAllValues() != (atomicord32)(g_aoTestValue32 | g_aoTestMask32))
		{
			break;
		}

		afTestFlags.SetFlagsMaskValue(g_aoTestValue32, false);

		if (afTestFlags.QueryFlagsAllValues() != (atomicord32)(~g_aoTestValue32 & g_aoTestMask32))
		{
			break;
		}
		

		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestAtomicFlags_SignalFlagsMaskValue()
{
	bool bResult = false;
	
	do
	{
		CAtomicFlags afTestFlags(g_aoTestValue32);
		
		afTestFlags.SignalFlagsMaskValue(g_aoTestMask32);
		
		if (afTestFlags.QueryFlagsAllValues() != (atomicord32)(g_aoTestValue32 | g_aoTestMask32))
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestAtomicFlags_DropFlagsMaskValue()
{
	bool bResult = false;
	
	do
	{
		CAtomicFlags afTestFlags(g_aoTestValue32);
		
		afTestFlags.DropFlagsMaskValue(g_aoTestMask32);
		
		if (afTestFlags.QueryFlagsAllValues() != (atomicord32)(g_aoTestValue32 & ~g_aoTestMask32))
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestAtomicFlags_ToggleSingleFlagValue()
{
	bool bResult = false;
	
	do
	{
		CAtomicFlags afTestFlags(g_aoTestValue32);
		
		bool bPreviousValue = afTestFlags.ToggleSingleFlagValue(g_aoTestBit32);
		
		if (bPreviousValue != ((g_aoTestValue32 & g_aoTestBit32) != 0) || afTestFlags.QueryFlagsAllValues() != (atomicord32)(g_aoTestValue32 ^ g_aoTestBit32))
		{
			break;
		}

		bool bAnotherPreviousValue = afTestFlags.ToggleSingleFlagValue(g_aoTestBit32);
		
		if (bAnotherPreviousValue == bPreviousValue || afTestFlags.QueryFlagsAllValues() != g_aoTestValue32)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestAtomicFlags_ModifySingleFlagValue()
{
	bool bResult = false;
	
	do
	{
		CAtomicFlags afTestFlags(g_aoTestValue32);
		
		bool bFirstModification = afTestFlags.ModifySingleFlagValue(g_aoTestBit32, true);
		
		if (bFirstModification != ((g_aoTestValue32 & g_aoTestBit32) != g_aoTestBit32) || afTestFlags.QueryFlagsAllValues() != (atomicord32)(g_aoTestValue32 | g_aoTestBit32))
		{
			break;
		}
		
		bool bAnotherModification = afTestFlags.ModifySingleFlagValue(g_aoTestBit32, bFirstModification);
		
		if (bAnotherModification == bFirstModification || afTestFlags.QueryFlagsAllValues() != (bFirstModification ? (atomicord32)(g_aoTestValue32 | g_aoTestBit32) : (atomicord32)(g_aoTestValue32 & ~g_aoTestBit32)))
		{
			break;
		}

		bool bYetAnotherModification = afTestFlags.ModifySingleFlagValue(g_aoTestBit32, bAnotherModification);

		if (bYetAnotherModification != bAnotherModification || afTestFlags.QueryFlagsAllValues() != (bAnotherModification ? (atomicord32)(g_aoTestValue32 | g_aoTestBit32) : (atomicord32)(g_aoTestValue32 & ~g_aoTestBit32)))
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestAtomicFlags_AssignFlagsByMask()
{
	bool bResult = false;
	
	do
	{
		CAtomicFlags afTestFlags(g_aoTestValue32);

		atomicord32 aoPreviousFlags = afTestFlags.AssignFlagsByMask(g_aoTestMask32, g_aoTestMask32);

		const atomicord32 aoNewFlags = (g_aoTestValue32 & ~g_aoTestMask32) | g_aoTestMask32;

		if (aoPreviousFlags != g_aoTestValue32 || afTestFlags.QueryFlagsAllValues() != aoNewFlags)
		{
			break;
		}

		atomicord32 aoAnotherPreviousFlags = afTestFlags.AssignFlagsByMask(g_aoTestValue32, 0);

		const atomicord32 aoAnotherNewFlags = aoNewFlags & ~g_aoTestValue32;

		if (aoAnotherPreviousFlags != aoNewFlags || afTestFlags.QueryFlagsAllValues() != aoAnotherNewFlags)
		{
			break;
		}
	
		atomicord32 aoYetAnotherPreviousFlags = afTestFlags.AssignFlagsByMask(g_aoTestMask32, g_aoTestMask32 & g_aoTestValue32);
		OU_ASSERT((g_aoTestMask32 & g_aoTestValue32) != 0); // Test degeneration
		
		const atomicord32 aoYetAnotherNewFlags = (aoAnotherNewFlags & ~g_aoTestMask32) | (g_aoTestMask32 & g_aoTestValue32);
		OU_ASSERT(aoYetAnotherNewFlags != (atomicord32)OU_UINT32_MAX); // Test degeneration
		
		if (aoYetAnotherPreviousFlags != aoAnotherNewFlags || afTestFlags.QueryFlagsAllValues() != aoYetAnotherNewFlags)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestAtomicFlags_AlterFlagsByMask()
{
	bool bResult = false;
	
	do
	{
		CAtomicFlags afTestFlags(g_aoTestValue32);
		
		bool bWasModification = afTestFlags.AlterFlagsByMask(g_aoTestMask32, g_aoTestMask32);
		
		const atomicord32 aoNewFlags = (g_aoTestValue32 & ~g_aoTestMask32) | g_aoTestMask32;
		
		if (bWasModification != ((g_aoTestValue32 & g_aoTestMask32) != g_aoTestMask32) || afTestFlags.QueryFlagsAllValues() != aoNewFlags)
		{
			break;
		}
		
		bool bWasAnotherModification = afTestFlags.AlterFlagsByMask(g_aoTestValue32, 0);
		
		const atomicord32 aoAnotherNewFlags = aoNewFlags & ~g_aoTestValue32;
		
		if (bWasAnotherModification != ((aoNewFlags & g_aoTestValue32) != 0) || afTestFlags.QueryFlagsAllValues() != aoAnotherNewFlags)
		{
			break;
		}
		
		bool bWasAnotherModificationRepeated = afTestFlags.AlterFlagsByMask(g_aoTestValue32, 0);
		
		if (bWasAnotherModificationRepeated || afTestFlags.QueryFlagsAllValues() != aoAnotherNewFlags)
		{
			break;
		}
		
		bool bWasYetAnotherModification = afTestFlags.AlterFlagsByMask(g_aoTestMask32, g_aoTestMask32 & g_aoTestValue32);
		OU_ASSERT((g_aoTestMask32 & g_aoTestValue32) != 0); // Test degeneration
		
		const atomicord32 aoYetAnotherNewFlags = (aoAnotherNewFlags & ~g_aoTestMask32) | (g_aoTestMask32 & g_aoTestValue32);
		OU_ASSERT(aoYetAnotherNewFlags != (atomicord32)OU_UINT32_MAX); // Test degeneration
		
		if (bWasYetAnotherModification != ((aoAnotherNewFlags & g_aoTestMask32) != (g_aoTestMask32 & g_aoTestValue32)) || afTestFlags.QueryFlagsAllValues() != aoYetAnotherNewFlags)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestAtomicFlags_GetFlagsMaskValue()
{
	bool bResult = false;
	
	do
	{
		CAtomicFlags afTestFlags(g_aoTestValue32);
		
		if (afTestFlags.GetFlagsMaskValue(g_aoTestMask32) != ((g_aoTestValue32 & g_aoTestMask32) != 0))
		{
			break;
		}
		
		if (afTestFlags.GetFlagsMaskValue(~g_aoTestValue32))
		{
			break;
		}
		
		if (!afTestFlags.GetFlagsMaskValue(OU_UINT32_MAX))
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestAtomicFlags_QueryFlagsByMask()
{
	bool bResult = false;
	
	do
	{
		CAtomicFlags afTestFlags(g_aoTestValue32);
		
		if (afTestFlags.QueryFlagsByMask(g_aoTestMask32) != (atomicord32)(g_aoTestValue32 & g_aoTestMask32))
		{
			break;
		}
		
		if (afTestFlags.QueryFlagsByMask(0))
		{
			break;
		}
		
		if (afTestFlags.QueryFlagsByMask(OU_UINT32_MAX) != g_aoTestValue32)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestAtomicFlags_OnlySignalSingleFlagOutOfMask()
{
	bool bResult = false;
	
	do
	{
		CAtomicFlags afTestFlags(g_aoTestValue32);
		OU_ASSERT(g_aoTestValue32 != 0); // Test degeneration
		
		if (afTestFlags.OnlySignalSingleFlagOutOfMask(OU_UINT32_MAX, g_aoTestBit32))
		{
			break;
		}

		if (afTestFlags.QueryFlagsAllValues() != g_aoTestValue32)
		{
			break;
		}
		
		afTestFlags.AssignFlagsAllValues(0);

		if (!afTestFlags.OnlySignalSingleFlagOutOfMask(g_aoTestBit32, g_aoTestBit32))
		{
			break;
		}
		
		if (afTestFlags.QueryFlagsAllValues() != g_aoTestBit32)
		{
			break;
		}
		
		if (afTestFlags.OnlySignalSingleFlagOutOfMask(g_aoTestBit32, g_aoTestBit32))
		{
			break;
		}
		
		if (afTestFlags.QueryFlagsAllValues() != g_aoTestBit32)
		{
			break;
		}
		
		if (afTestFlags.OnlySignalSingleFlagOutOfMask(OU_UINT32_MAX, g_aoTestAnotherBit32))
		{
			break;
		}
		
		if (afTestFlags.QueryFlagsAllValues() != g_aoTestBit32)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestAtomicFlags_EnumSetEnumeratedFlagValue()
{
	bool bResult = false;
	
	do
	{
		CAtomicFlags afTestFlags;
		
		afTestFlags.EnumSetEnumeratedFlagValue(1, 0, OU_UINT32_BITS, true);

		if (afTestFlags.QueryFlagsAllValues() != 1)
		{
			break;
		}
	
		afTestFlags.EnumSetEnumeratedFlagValue(1, OU_UINT32_BITS - 1, OU_UINT32_BITS, true);
		
		if (afTestFlags.QueryFlagsAllValues() != (atomicord32)(OU_INT32_MIN + 1))
		{
			break;
		}
		
		afTestFlags.EnumSetEnumeratedFlagValue(1, 0, OU_UINT32_BITS, false);
		
		if (afTestFlags.QueryFlagsAllValues() != (atomicord32)OU_INT32_MIN)
		{
			break;
		}
		
		afTestFlags.EnumSetEnumeratedFlagValue(1, OU_UINT32_BITS - 1, OU_UINT32_BITS, false);
		
		if (afTestFlags.QueryFlagsAllValues() != 0)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestAtomicFlags_EnumSignalEnumeratedFlagValue()
{
	bool bResult = false;
	
	do
	{
		CAtomicFlags afTestFlags;
		
		afTestFlags.EnumSignalEnumeratedFlagValue(1, 0, OU_UINT32_BITS);
		
		if (afTestFlags.QueryFlagsAllValues() != 1)
		{
			break;
		}
		
		afTestFlags.EnumSignalEnumeratedFlagValue(1, OU_UINT32_BITS - 1, OU_UINT32_BITS);
		
		if (afTestFlags.QueryFlagsAllValues() != (atomicord32)(OU_INT32_MIN + 1))
		{
			break;
		}
		
		afTestFlags.EnumSignalEnumeratedFlagValue(1, 0, OU_UINT32_BITS);
		
		if (afTestFlags.QueryFlagsAllValues() != (atomicord32)(OU_INT32_MIN + 1))
		{
			break;
		}
		
		afTestFlags.EnumSignalEnumeratedFlagValue(1, OU_UINT32_BITS - 1, OU_UINT32_BITS);
		
		if (afTestFlags.QueryFlagsAllValues() != (atomicord32)(OU_INT32_MIN + 1))
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestAtomicFlags_EnumDropEnumeratedFlagValue()
{
	bool bResult = false;
	
	do
	{
		CAtomicFlags afTestFlags(OU_UINT32_MAX);
		
		afTestFlags.EnumDropEnumeratedFlagValue(1, 0, OU_UINT32_BITS);
		
		if (afTestFlags.QueryFlagsAllValues() != (atomicord32)(OU_UINT32_MAX ^ 1))
		{
			break;
		}
		
		afTestFlags.EnumDropEnumeratedFlagValue(1, OU_UINT32_BITS - 1, OU_UINT32_BITS);
		
		if (afTestFlags.QueryFlagsAllValues() != (atomicord32)~(OU_INT32_MIN + 1))
		{
			break;
		}
		
		afTestFlags.EnumDropEnumeratedFlagValue(1, 0, OU_UINT32_BITS);
		
		if (afTestFlags.QueryFlagsAllValues() != (atomicord32)~(OU_INT32_MIN + 1))
		{
			break;
		}
		
		afTestFlags.EnumDropEnumeratedFlagValue(1, OU_UINT32_BITS - 1, OU_UINT32_BITS);
		
		if (afTestFlags.QueryFlagsAllValues() != (atomicord32)~(OU_INT32_MIN + 1))
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestAtomicFlags_EnumToggleEnumeratedFlagValue()
{
	bool bResult = false;
	
	do
	{
		CAtomicFlags afTestFlags;
		
		bool bToggleFirstResult = afTestFlags.EnumToggleEnumeratedFlagValue(1, 0, OU_UINT32_BITS);
		
		if (bToggleFirstResult || afTestFlags.QueryFlagsAllValues() != 1)
		{
			break;
		}
		
		bool bToggleSecondResult = afTestFlags.EnumToggleEnumeratedFlagValue(1, OU_UINT32_BITS - 1, OU_UINT32_BITS);
		
		if (bToggleSecondResult || afTestFlags.QueryFlagsAllValues() != (atomicord32)(OU_INT32_MIN + 1))
		{
			break;
		}
		
		bool bToggleThirdResult = afTestFlags.EnumToggleEnumeratedFlagValue(1, 0, OU_UINT32_BITS);
		
		if (!bToggleThirdResult || afTestFlags.QueryFlagsAllValues() != (atomicord32)OU_INT32_MIN)
		{
			break;
		}
		
		bool bToggleFourthResult = afTestFlags.EnumToggleEnumeratedFlagValue(1, OU_UINT32_BITS - 1, OU_UINT32_BITS);
		
		if (!bToggleFourthResult || afTestFlags.QueryFlagsAllValues() != 0)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestAtomicFlags_EnumModifyEnumeratedFlagValue()
{
	bool bResult = false;
	
	do
	{
		CAtomicFlags afTestFlags;
		
		bool bModifyFirstResult = afTestFlags.EnumModifyEnumeratedFlagValue(1, 0, OU_UINT32_BITS, true);
		
		if (!bModifyFirstResult || afTestFlags.QueryFlagsAllValues() != 1)
		{
			break;
		}
		
		bool bModifySecondResult = afTestFlags.EnumModifyEnumeratedFlagValue(1, OU_UINT32_BITS - 1, OU_UINT32_BITS, true);
		
		if (!bModifySecondResult || afTestFlags.QueryFlagsAllValues() != (atomicord32)(OU_INT32_MIN + 1))
		{
			break;
		}
		
		bool bModifyThirdResult = afTestFlags.EnumModifyEnumeratedFlagValue(1, 0, OU_UINT32_BITS, true);
		
		if (bModifyThirdResult || afTestFlags.QueryFlagsAllValues() != (atomicord32)(OU_INT32_MIN + 1))
		{
			break;
		}
		
		bool bModifyFourthResult = afTestFlags.EnumModifyEnumeratedFlagValue(1, OU_UINT32_BITS - 1, OU_UINT32_BITS, true);
		
		if (bModifyFourthResult || afTestFlags.QueryFlagsAllValues() != (atomicord32)(OU_INT32_MIN + 1))
		{
			break;
		}
		
		bool bModifyFifthResult = afTestFlags.EnumModifyEnumeratedFlagValue(1, 0, OU_UINT32_BITS, false);
		
		if (!bModifyFifthResult || afTestFlags.QueryFlagsAllValues() != (atomicord32)OU_INT32_MIN)
		{
			break;
		}
		
		bool bModifySixthResult = afTestFlags.EnumModifyEnumeratedFlagValue(1, OU_UINT32_BITS - 1, OU_UINT32_BITS, false);
		
		if (!bModifySixthResult || afTestFlags.QueryFlagsAllValues() != 0)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestAtomicFlags_EnumSignalFirstEnumeratedFlagValue()
{
	bool bResult = false;
	
	do
	{
		CAtomicFlags afTestFlags;

		bool bFirstResult = afTestFlags.EnumSignalFirstEnumeratedFlagValue(1, 0, OU_UINT32_BITS);

		if (!bFirstResult || afTestFlags.QueryFlagsAllValues() != 1)
		{
			break;
		}
		
		bool bSecondResult = afTestFlags.EnumSignalFirstEnumeratedFlagValue(1, 0, OU_UINT32_BITS);
		
		if (bSecondResult || afTestFlags.QueryFlagsAllValues() != 1)
		{
			break;
		}
		
		bool bThirdResult = afTestFlags.EnumSignalFirstEnumeratedFlagValue(2, 0, OU_UINT32_BITS - 1);
		
		if (!bThirdResult || afTestFlags.QueryFlagsAllValues() != 3)
		{
			break;
		}
		
		bool bFourthResult = afTestFlags.EnumSignalFirstEnumeratedFlagValue(1, OU_UINT32_BITS - 1, OU_UINT32_BITS);
		
		if (bFourthResult || afTestFlags.QueryFlagsAllValues() != (atomicord32)(OU_INT32_MIN + 3))
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestAtomicFlags_EnumSignalLastEnumeratedFlagValue()
{
	bool bResult = false;
	
	do
	{
		CAtomicFlags afTestFlags;
		
		bool bFirstResult = afTestFlags.EnumSignalLastEnumeratedFlagValue(1, 0, 1);
		
		if (!bFirstResult || afTestFlags.QueryFlagsAllValues() != 1)
		{
			break;
		}
		
		bool bSecondResult = afTestFlags.EnumSignalLastEnumeratedFlagValue(1, 0, 1);
		
		if (bSecondResult || afTestFlags.QueryFlagsAllValues() != 1)
		{
			break;
		}
		
		bool bThirdResult = afTestFlags.EnumSignalLastEnumeratedFlagValue(1, 1, 2);
		
		if (!bThirdResult || afTestFlags.QueryFlagsAllValues() != 3)
		{
			break;
		}
		
		bool bFourthResult = afTestFlags.EnumSignalLastEnumeratedFlagValue(1, OU_UINT32_BITS - 1, OU_UINT32_BITS);
		
		if (bFourthResult || afTestFlags.QueryFlagsAllValues() != (atomicord32)(OU_INT32_MIN + 3))
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestAtomicFlags_EnumGetEnumeratedFlagValue()
{
	bool bResult = false;
	
	do
	{
		CAtomicFlags afTestFlags((atomicord32)(OU_INT32_MIN + 1));
		
		if (!afTestFlags.EnumGetEnumeratedFlagValue(1, 0, OU_UINT32_BITS))
		{
			break;
		}
	
		if (afTestFlags.EnumGetEnumeratedFlagValue(2, 0, OU_UINT32_BITS - 1))
		{
			break;
		}
		
		if (afTestFlags.EnumGetEnumeratedFlagValue(1, 1, OU_UINT32_BITS - 1))
		{
			break;
		}
		
		if (!afTestFlags.EnumGetEnumeratedFlagValue(1, OU_UINT32_BITS - 1, OU_UINT32_BITS))
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestAtomicFlags_EnumFindFirstEnumeratedFlag()
{
	bool bResult = false;
	
	do
	{
		CAtomicFlags afTestFlags((atomicord32)(OU_INT32_MIN + 1));

		unsigned int uiFirstResult = afTestFlags.EnumFindFirstEnumeratedFlag(1, OU_UINT32_BITS);
		if (uiFirstResult != 0)
		{
			break;
		}

		unsigned int uiSecondResult = afTestFlags.EnumFindFirstEnumeratedFlag(2, OU_UINT32_BITS - 1);
		if (uiSecondResult != OU_UINT32_BITS - 2)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestAtomicFlags_EnumAllSignalEnumeratedFlags()
{
	bool bResult = false;
	
	do
	{
		CAtomicFlags afTestFlags;
		
		afTestFlags.EnumAllSignalEnumeratedFlags(1, 1);

		if (afTestFlags.QueryFlagsAllValues() != 1)
		{
			break;
		}

		afTestFlags.EnumAllSignalEnumeratedFlags(4, OU_UINT32_BITS - 2);

		if (afTestFlags.QueryFlagsAllValues() != (atomicord32)(OU_UINT32_MAX ^ 2))
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestAtomicFlags_EnumAllDropEnumeratedFlags()
{
	bool bResult = false;
	
	do
	{
		CAtomicFlags afTestFlags(OU_UINT32_MAX);
		
		afTestFlags.EnumAllDropEnumeratedFlags(1, 1);
		
		if (afTestFlags.QueryFlagsAllValues() != (atomicord32)(OU_UINT32_MAX ^ 1))
		{
			break;
		}
		
		afTestFlags.EnumAllDropEnumeratedFlags(4, OU_UINT32_BITS - 2);
		
		if (afTestFlags.QueryFlagsAllValues() != 2)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestAtomicFlags_EnumAllQueryEnumeratedFlags()
{
	bool bResult = false;
	
	do
	{
		CAtomicFlags afTestFlags((atomicord32)(OU_INT32_MIN + 1));
		
		atomicord32 aoFirstResult = afTestFlags.EnumAllQueryEnumeratedFlags(1, OU_UINT32_BITS);
		if (aoFirstResult != (atomicord32)(OU_INT32_MIN + 1))
		{
			break;
		}
		
		atomicord32 aoSecondResult = afTestFlags.EnumAllQueryEnumeratedFlags(2, OU_UINT32_BITS - 1);
		if (aoSecondResult != (atomicord32)(OU_INT32_MIN))
		{
			break;
		}
		
		atomicord32 aoThirdResult = afTestFlags.EnumAllQueryEnumeratedFlags(2, OU_UINT32_BITS - 2);
		if (aoThirdResult != 0)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestAtomicFlags_EnumAnyGetEnumeratedFlagValue()
{
	bool bResult = false;
	
	do
	{
		CAtomicFlags afTestFlags((atomicord32)(OU_INT32_MIN + 1));
		
		bool bFirstResult = afTestFlags.EnumAnyGetEnumeratedFlagValue(1, OU_UINT32_BITS);
		if (!bFirstResult)
		{
			break;
		}
		
		bool bSecondResult = afTestFlags.EnumAnyGetEnumeratedFlagValue(2, OU_UINT32_BITS - 1);
		if (!bSecondResult)
		{
			break;
		}
		
		bool bThirdResult = afTestFlags.EnumAnyGetEnumeratedFlagValue(2, OU_UINT32_BITS - 2);
		if (bThirdResult)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestAtomicFlags_StoreFlagsEnumeratedValue()
{
	bool bResult = false;
	
	do
	{
		CAtomicFlags afTestFlags;

		afTestFlags.StoreFlagsEnumeratedValue(0x03, 1, 2);

		if (afTestFlags.QueryFlagsAllValues() != (atomicord32)(2 << 1))
		{
			break;
		}
	
		afTestFlags.StoreFlagsEnumeratedValue(0x03, OU_UINT32_BITS - 2, 3);
		
		if (afTestFlags.QueryFlagsAllValues() != ((atomicord32)(2 << 1) | (atomicord32)(OU_INT32_MIN | (OU_INT32_MIN >> 1))))
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestAtomicFlags_RetrieveFlagsEnumeratedValue()
{
	bool bResult = false;
	
	do
	{
		CAtomicFlags afTestFlags((atomicord32)(OU_INT32_MIN + 1));
		
		unsigned int aoFirstResult = afTestFlags.RetrieveFlagsEnumeratedValue(0x3, 1);
		if (aoFirstResult != 0)
		{
			break;
		}
		
		unsigned int aoSecondResult = afTestFlags.RetrieveFlagsEnumeratedValue(0x3, OU_UINT32_BITS - 2);
		if (aoSecondResult != 2)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}


enum EOUATOMICFLAGSFEATURE
{
	OAF__MIN,
		
	OAF_CONSTRUCTORS = OAF__MIN,
	OAF_ASSIGNFLAGSALLVALUES,
	OAF_QUERYFLAGSALLVALUES,
	OAF_SETFLAGSMASKVALUE,
	OAF_SIGNALFLAGSMASKVALUE,
	OAF_DROPFLAGSMASKVALUE,
	OAF_TOGGLESINGLEFLAGVALUE,
	OAF_MODIFYSINGLEFLAGVALUE,
	OAF_ASSIGNFLAGSBYMASK,
	OAF_ALTERFLAGSBYMASK,
	OAF_GETFLAGSMASKVALUE,
	OAF_QUERYFLAGSBYMASK,
	OAF_ONLYSIGNALSINGLEFLAGOUTOFMASK,
	OAF_ENUMSETENUMERATEDFLAGVALUE,
	OAF_ENUMSIGNALENUMERATEDFLAGVALUE,
	OAF_ENUMDROPENUMERATEDFLAGVALUE,
	OAF_ENUMTOGGLEENUMERATEDFLAGVALUE,
	OAF_ENUMMODIFYENUMERATEDFLAGVALUE,
	OAF_ENUMSIGNALFIRSTENUMERATEDFLAGVALUE,
	OAF_ENUMSIGNALLASTENUMERATEDFLAGVALUE,
	OAF_ENUMGETENUMERATEDFLAGVALUE,
	OAF_ENUMFINDFIRSTENUMERATEDFLAG,
	OAF_ENUMALLSIGNALENUMERATEDFLAGS,
	OAF_ENUMALLDROPENUMERATEDFLAGS,
	OAF_ENUMALLQUERYENUMERATEDFLAGS,
	OAF_ENUMANYGETENUMERATEDFLAGVALUE,
	OAF_STOREFLAGSENUMERATEDVALUE,
	OAF_RETRIEVEFLAGSENUMERATEDVALUE,

	OAF__MAX,
};

template<>
CFeatureTestProcedure const CEnumUnsortedElementArray<EOUATOMICFLAGSFEATURE, OAF__MAX, CFeatureTestProcedure>::m_aetElementArray[] =
{
	&TestAtomicFlags_Constructors, // OAF_CONSTRUCTORS
	&TestAtomicFlags_AssignFlagsAllValues, // OAF_ASSIGNFLAGSALLVALUES,
	&TestAtomicFlags_QueryFlagsAllValues, // OAF_QUERYFLAGSALLVALUES,
	&TestAtomicFlags_SetFlagsMaskValue, // OAF_SETFLAGSMASKVALUE,
	&TestAtomicFlags_SignalFlagsMaskValue, // OAF_SIGNALFLAGSMASKVALUE,
	&TestAtomicFlags_DropFlagsMaskValue, // OAF_DROPFLAGSMASKVALUE,
	&TestAtomicFlags_ToggleSingleFlagValue, // OAF_TOGGLESINGLEFLAGVALUE,
	&TestAtomicFlags_ModifySingleFlagValue, // OAF_MODIFYSINGLEFLAGVALUE,
	&TestAtomicFlags_AssignFlagsByMask, // OAF_ASSIGNFLAGSBYMASK,
	&TestAtomicFlags_AlterFlagsByMask, // OAF_ALTERFLAGSBYMASK,
	&TestAtomicFlags_GetFlagsMaskValue, // OAF_GETFLAGSMASKVALUE,
	&TestAtomicFlags_QueryFlagsByMask, // OAF_QUERYFLAGSBYMASK,
	&TestAtomicFlags_OnlySignalSingleFlagOutOfMask, // OAF_ONLYSIGNALSINGLEFLAGOUTOFMASK,
	&TestAtomicFlags_EnumSetEnumeratedFlagValue, // OAF_ENUMSETENUMERATEDFLAGVALUE,
	&TestAtomicFlags_EnumSignalEnumeratedFlagValue, // OAF_ENUMSIGNALENUMERATEDFLAGVALUE,
	&TestAtomicFlags_EnumDropEnumeratedFlagValue, // OAF_ENUMDROPENUMERATEDFLAGVALUE,
	&TestAtomicFlags_EnumToggleEnumeratedFlagValue, // OAF_ENUMTOGGLEENUMERATEDFLAGVALUE,
	&TestAtomicFlags_EnumModifyEnumeratedFlagValue, // OAF_ENUMMODIFYENUMERATEDFLAGVALUE,
	&TestAtomicFlags_EnumSignalFirstEnumeratedFlagValue, // OAF_ENUMSIGNALFIRSTENUMERATEDFLAGVALUE,
	&TestAtomicFlags_EnumSignalLastEnumeratedFlagValue, // OAF_ENUMSIGNALLASTENUMERATEDFLAGVALUE,
	&TestAtomicFlags_EnumGetEnumeratedFlagValue, // OAF_ENUMGETENUMERATEDFLAGVALUE,
	&TestAtomicFlags_EnumFindFirstEnumeratedFlag, // OAF_ENUMFINDFIRSTENUMERATEDFLAG,
	&TestAtomicFlags_EnumAllSignalEnumeratedFlags, // OAF_ENUMALLSIGNALENUMERATEDFLAGS,
	&TestAtomicFlags_EnumAllDropEnumeratedFlags, // OAF_ENUMALLDROPENUMERATEDFLAGS,
	&TestAtomicFlags_EnumAllQueryEnumeratedFlags, // OAF_ENUMALLQUERYENUMERATEDFLAGS,
	&TestAtomicFlags_EnumAnyGetEnumeratedFlagValue, // OAF_ENUMANYGETENUMERATEDFLAGVALUE,
	&TestAtomicFlags_StoreFlagsEnumeratedValue, // OAF_STOREFLAGSENUMERATEDVALUE,
	&TestAtomicFlags_RetrieveFlagsEnumeratedValue, // OAF_RETRIEVEFLAGSENUMERATEDVALUE,
};
static const CEnumUnsortedElementArray<EOUATOMICFLAGSFEATURE, OAF__MAX, CFeatureTestProcedure> g_afnAtomicFlagsFeatureTestProcedures;

template<>
const char *const CEnumUnsortedElementArray<EOUATOMICFLAGSFEATURE, OAF__MAX, const char *>::m_aetElementArray[] =
{
	"Constructors", // OAF_CONSTRUCTORS
	"AssignFlagsAllValues", // OAF_ASSIGNFLAGSALLVALUES,
	"QueryFlagsAllValues", // OAF_QUERYFLAGSALLVALUES,
	"SetFlagsMaskValue", // OAF_SETFLAGSMASKVALUE,
	"SignalFlagsMaskValue", // OAF_SIGNALFLAGSMASKVALUE,
	"DropFlagsMaskValue", // OAF_DROPFLAGSMASKVALUE,
	"ToggleSingleFlagValue", // OAF_TOGGLESINGLEFLAGVALUE,
	"ModifySingleFlagValue", // OAF_MODIFYSINGLEFLAGVALUE,
	"AssignFlagsByMask", // OAF_ASSIGNFLAGSBYMASK,
	"AlterFlagsByMask", // OAF_ALTERFLAGSBYMASK,
	"GetFlagsMaskValue", // OAF_GETFLAGSMASKVALUE,
	"QueryFlagsByMask", // OAF_QUERYFLAGSBYMASK,
	"OnlySignalSingleFlagOutOfMask", // OAF_ONLYSIGNALSINGLEFLAGOUTOFMASK,
	"EnumSetEnumeratedFlagValue", // OAF_ENUMSETENUMERATEDFLAGVALUE,
	"EnumSignalEnumeratedFlagValue", // OAF_ENUMSIGNALENUMERATEDFLAGVALUE,
	"EnumDropEnumeratedFlagValue", // OAF_ENUMDROPENUMERATEDFLAGVALUE,
	"EnumToggleEnumeratedFlagValue", // OAF_ENUMTOGGLEENUMERATEDFLAGVALUE,
	"EnumModifyEnumeratedFlagValue", // OAF_ENUMMODIFYENUMERATEDFLAGVALUE,
	"EnumSignalFirstEnumeratedFlagValue", // OAF_ENUMSIGNALFIRSTENUMERATEDFLAGVALUE,
	"EnumSignalLastEnumeratedFlagValue", // OAF_ENUMSIGNALLASTENUMERATEDFLAGVALUE,
	"EnumGetEnumeratedFlagValue", // OAF_ENUMGETENUMERATEDFLAGVALUE,
	"EnumFindFirstEnumeratedFlag", // OAF_ENUMFINDFIRSTENUMERATEDFLAG,
	"EnumAllSignalEnumeratedFlags", // OAF_ENUMALLSIGNALENUMERATEDFLAGS,
	"EnumAllDropEnumeratedFlags", // OAF_ENUMALLDROPENUMERATEDFLAGS,
	"EnumAllQueryEnumeratedFlags", // OAF_ENUMALLQUERYENUMERATEDFLAGS,
	"EnumAnyGetEnumeratedFlagValue", // OAF_ENUMANYGETENUMERATEDFLAGVALUE,
	"StoreFlagsEnumeratedValue", // OAF_STOREFLAGSENUMERATEDVALUE,
	"RetrieveFlagsEnumeratedValue", // OAF_RETRIEVEFLAGSENUMERATEDVALUE,
};
static const CEnumUnsortedElementArray<EOUATOMICFLAGSFEATURE, OAF__MAX, const char *> g_aszAtomicFlagsFeatureTestNames;


bool TestAtomicFlags(unsigned int &nOutSuccessCount, unsigned int &nOutTestCount)
{
	bool bResult = false;
	nOutSuccessCount = 0;
	nOutTestCount = OAF__MAX;
	
	bool bAPIInitialized = false;
	
	do
	{
		if (!InitializeAtomicAPI())
		{
			break;
		}
		
		bAPIInitialized = true;
		
		if (!TestSubsystem(nOutSuccessCount, nOutTestCount, OAF__MAX, g_aszAtomicFlagsFeatureTestNames.GetStoragePointer(), g_afnAtomicFlagsFeatureTestProcedures.GetStoragePointer()))
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	if (bAPIInitialized)
	{
		FinalizeAtomicAPI();
	}
	
	return bResult;
}


//////////////////////////////////////////////////////////////////////////

typedef CSimpleFlagsTemplate<uint64ou> CSimpleFlags64;

const uint64ou g_uiTestValue64 = ((uint64ou)0xA5A5A5A5 << 32) | 0xA5A5A5A5;
const uint64ou g_uiTestMask64 = ((uint64ou)0xC6C6C6C6 << 32) | 0xC6C6C6C6;
const uint64ou g_uiTestBit64 = (uint64ou)OU_INT64_MIN;
const uint64ou g_uiTestAnotherBit64 = (uint64ou)((uint64ou)OU_INT64_MIN >> 1);


bool TestSimpleFlags64_Constructors()
{
	bool bResult = false;
	
	do
	{
		if (sizeof(CSimpleFlags64::value_type) != sizeof(uint64ou) || sizeof(CSimpleFlags64) != sizeof(uint64ou))
		{
			break;
		}

		CSimpleFlags64 sfEmptyFlags;

		if (sfEmptyFlags.QueryFlagsAllValues())
		{
			break;
		}

		CSimpleFlags64 sfFullFlags(OU_UINT64_MAX);
		
		if (sfFullFlags.QueryFlagsAllValues() != OU_UINT64_MAX)
		{
			break;
		}

		CSimpleFlags64 sfCopyOfFullFlags(sfFullFlags);

		if (sfCopyOfFullFlags.QueryFlagsAllValues() != OU_UINT64_MAX)
		{
			break;
		}
	
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags64_AssignFlagsAllValues()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags64 sfTestFlags;

		sfTestFlags.AssignFlagsAllValues(OU_UINT64_MAX);

		if (sfTestFlags.QueryFlagsAllValues() != OU_UINT64_MAX)
		{
			break;
		}

		sfTestFlags.AssignFlagsAllValues(0);

		if (sfTestFlags.QueryFlagsAllValues() != 0)
		{
			break;
		}
	
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags64_QueryFlagsAllValues()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags64 sfTestFlags(g_uiTestValue64);
		
		if (sfTestFlags.QueryFlagsAllValues() != g_uiTestValue64)
		{
			break;
		}

		// Double check to be sure ;-)
		if (sfTestFlags.QueryFlagsAllValues() != g_uiTestValue64)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags64_SetFlagsMaskValue()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags64 sfTestFlags(g_uiTestValue64);

		sfTestFlags.SetFlagsMaskValue(g_uiTestMask64, true);

		if (sfTestFlags.QueryFlagsAllValues() != (uint64ou)(g_uiTestValue64 | g_uiTestMask64))
		{
			break;
		}

		sfTestFlags.SetFlagsMaskValue(g_uiTestValue64, false);

		if (sfTestFlags.QueryFlagsAllValues() != (uint64ou)(~g_uiTestValue64 & g_uiTestMask64))
		{
			break;
		}
		

		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags64_SignalFlagsMaskValue()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags64 sfTestFlags(g_uiTestValue64);
		
		sfTestFlags.SignalFlagsMaskValue(g_uiTestMask64);
		
		if (sfTestFlags.QueryFlagsAllValues() != (uint64ou)(g_uiTestValue64 | g_uiTestMask64))
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags64_DropFlagsMaskValue()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags64 sfTestFlags(g_uiTestValue64);
		
		sfTestFlags.DropFlagsMaskValue(g_uiTestMask64);
		
		if (sfTestFlags.QueryFlagsAllValues() != (uint64ou)(g_uiTestValue64 & ~g_uiTestMask64))
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags64_ToggleSingleFlagValue()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags64 sfTestFlags(g_uiTestValue64);
		
		bool bPreviousValue = sfTestFlags.ToggleSingleFlagValue(g_uiTestBit64);
		
		if (bPreviousValue != ((g_uiTestValue64 & g_uiTestBit64) != 0) || sfTestFlags.QueryFlagsAllValues() != (uint64ou)(g_uiTestValue64 ^ g_uiTestBit64))
		{
			break;
		}

		bool bAnotherPreviousValue = sfTestFlags.ToggleSingleFlagValue(g_uiTestBit64);
		
		if (bAnotherPreviousValue == bPreviousValue || sfTestFlags.QueryFlagsAllValues() != g_uiTestValue64)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags64_ModifySingleFlagValue()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags64 sfTestFlags(g_uiTestValue64);
		
		bool bFirstModification = sfTestFlags.ModifySingleFlagValue(g_uiTestBit64, true);
		
		if (bFirstModification != ((g_uiTestValue64 & g_uiTestBit64) != g_uiTestBit64) || sfTestFlags.QueryFlagsAllValues() != (uint64ou)(g_uiTestValue64 | g_uiTestBit64))
		{
			break;
		}
		
		bool bAnotherModification = sfTestFlags.ModifySingleFlagValue(g_uiTestBit64, bFirstModification);
		
		if (bAnotherModification == bFirstModification || sfTestFlags.QueryFlagsAllValues() != (bFirstModification ? (uint64ou)(g_uiTestValue64 | g_uiTestBit64) : (uint64ou)(g_uiTestValue64 & ~g_uiTestBit64)))
		{
			break;
		}

		bool bYetAnotherModification = sfTestFlags.ModifySingleFlagValue(g_uiTestBit64, bAnotherModification);

		if (bYetAnotherModification != bAnotherModification || sfTestFlags.QueryFlagsAllValues() != (bAnotherModification ? (uint64ou)(g_uiTestValue64 | g_uiTestBit64) : (uint64ou)(g_uiTestValue64 & ~g_uiTestBit64)))
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags64_AssignFlagsByMask()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags64 sfTestFlags(g_uiTestValue64);

		uint64ou uiPreviousFlags = sfTestFlags.AssignFlagsByMask(g_uiTestMask64, g_uiTestMask64);

		const uint64ou uiNewFlags = (g_uiTestValue64 & ~g_uiTestMask64) | g_uiTestMask64;

		if (uiPreviousFlags != g_uiTestValue64 || sfTestFlags.QueryFlagsAllValues() != uiNewFlags)
		{
			break;
		}

		uint64ou uiAnotherPreviousFlags = sfTestFlags.AssignFlagsByMask(g_uiTestValue64, 0);

		const uint64ou uiAnotherNewFlags = uiNewFlags & ~g_uiTestValue64;

		if (uiAnotherPreviousFlags != uiNewFlags || sfTestFlags.QueryFlagsAllValues() != uiAnotherNewFlags)
		{
			break;
		}
	
		uint64ou uiYetAnotherPreviousFlags = sfTestFlags.AssignFlagsByMask(g_uiTestMask64, g_uiTestMask64 & g_uiTestValue64);
		OU_ASSERT((g_uiTestMask64 & g_uiTestValue64) != 0); // Test degeneration
		
		const uint64ou uiYetAnotherNewFlags = (uiAnotherNewFlags & ~g_uiTestMask64) | (g_uiTestMask64 & g_uiTestValue64);
		OU_ASSERT(uiYetAnotherNewFlags != OU_UINT64_MAX); // Test degeneration
		
		if (uiYetAnotherPreviousFlags != uiAnotherNewFlags || sfTestFlags.QueryFlagsAllValues() != uiYetAnotherNewFlags)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags64_AlterFlagsByMask()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags64 sfTestFlags(g_uiTestValue64);
		
		bool bWasModification = sfTestFlags.AlterFlagsByMask(g_uiTestMask64, g_uiTestMask64);
		
		const uint64ou uiNewFlags = (g_uiTestValue64 & ~g_uiTestMask64) | g_uiTestMask64;
		
		if (bWasModification != ((g_uiTestValue64 & g_uiTestMask64) != g_uiTestMask64) || sfTestFlags.QueryFlagsAllValues() != uiNewFlags)
		{
			break;
		}
		
		bool bWasAnotherModification = sfTestFlags.AlterFlagsByMask(g_uiTestValue64, 0);
		
		const uint64ou uiAnotherNewFlags = uiNewFlags & ~g_uiTestValue64;
		
		if (bWasAnotherModification != ((uiNewFlags & g_uiTestValue64) != 0) || sfTestFlags.QueryFlagsAllValues() != uiAnotherNewFlags)
		{
			break;
		}
		
		bool bWasAnotherModificationRepeated = sfTestFlags.AlterFlagsByMask(g_uiTestValue64, 0);
		
		if (bWasAnotherModificationRepeated || sfTestFlags.QueryFlagsAllValues() != uiAnotherNewFlags)
		{
			break;
		}
		
		bool bWasYetAnotherModification = sfTestFlags.AlterFlagsByMask(g_uiTestMask64, g_uiTestMask64 & g_uiTestValue64);
		OU_ASSERT((g_uiTestMask64 & g_uiTestValue64) != 0); // Test degeneration
		
		const uint64ou uiYetAnotherNewFlags = (uiAnotherNewFlags & ~g_uiTestMask64) | (g_uiTestMask64 & g_uiTestValue64);
		OU_ASSERT(uiYetAnotherNewFlags != OU_UINT64_MAX); // Test degeneration
		
		if (bWasYetAnotherModification != ((uiAnotherNewFlags & g_uiTestMask64) != (g_uiTestMask64 & g_uiTestValue64)) || sfTestFlags.QueryFlagsAllValues() != uiYetAnotherNewFlags)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags64_GetFlagsMaskValue()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags64 sfTestFlags(g_uiTestValue64);
		
		if (sfTestFlags.GetFlagsMaskValue(g_uiTestMask64) != ((g_uiTestValue64 & g_uiTestMask64) != 0))
		{
			break;
		}
		
		if (sfTestFlags.GetFlagsMaskValue(~g_uiTestValue64))
		{
			break;
		}
		
		if (!sfTestFlags.GetFlagsMaskValue(OU_UINT64_MAX))
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags64_QueryFlagsByMask()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags64 sfTestFlags(g_uiTestValue64);
		
		if (sfTestFlags.QueryFlagsByMask(g_uiTestMask64) != (uint64ou)(g_uiTestValue64 & g_uiTestMask64))
		{
			break;
		}
		
		if (sfTestFlags.QueryFlagsByMask(0))
		{
			break;
		}
		
		if (sfTestFlags.QueryFlagsByMask(OU_UINT64_MAX) != g_uiTestValue64)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags64_OnlySignalSingleFlagOutOfMask()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags64 sfTestFlags(g_uiTestValue64);
		OU_ASSERT(g_uiTestValue64 != 0); // Test degeneration
		
		if (sfTestFlags.OnlySignalSingleFlagOutOfMask(OU_UINT64_MAX, g_uiTestBit64))
		{
			break;
		}

		if (sfTestFlags.QueryFlagsAllValues() != g_uiTestValue64)
		{
			break;
		}
		
		sfTestFlags.AssignFlagsAllValues(0);

		if (!sfTestFlags.OnlySignalSingleFlagOutOfMask(g_uiTestBit64, g_uiTestBit64))
		{
			break;
		}
		
		if (sfTestFlags.QueryFlagsAllValues() != g_uiTestBit64)
		{
			break;
		}
		
		if (sfTestFlags.OnlySignalSingleFlagOutOfMask(g_uiTestBit64, g_uiTestBit64))
		{
			break;
		}
		
		if (sfTestFlags.QueryFlagsAllValues() != g_uiTestBit64)
		{
			break;
		}
		
		if (sfTestFlags.OnlySignalSingleFlagOutOfMask(OU_UINT64_MAX, g_uiTestAnotherBit64))
		{
			break;
		}
		
		if (sfTestFlags.QueryFlagsAllValues() != g_uiTestBit64)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags64_EnumSetEnumeratedFlagValue()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags64 sfTestFlags;
		
		sfTestFlags.EnumSetEnumeratedFlagValue(1, 0, OU_UINT64_BITS, true);

		if (sfTestFlags.QueryFlagsAllValues() != 1)
		{
			break;
		}
	
		sfTestFlags.EnumSetEnumeratedFlagValue(1, OU_UINT64_BITS - 1, OU_UINT64_BITS, true);
		
		if (sfTestFlags.QueryFlagsAllValues() != (uint64ou)(OU_INT64_MIN + 1))
		{
			break;
		}
		
		sfTestFlags.EnumSetEnumeratedFlagValue(1, 0, OU_UINT64_BITS, false);
		
		if (sfTestFlags.QueryFlagsAllValues() != (uint64ou)OU_INT64_MIN)
		{
			break;
		}
		
		sfTestFlags.EnumSetEnumeratedFlagValue(1, OU_UINT64_BITS - 1, OU_UINT64_BITS, false);
		
		if (sfTestFlags.QueryFlagsAllValues() != 0)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags64_EnumSignalEnumeratedFlagValue()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags64 sfTestFlags;
		
		sfTestFlags.EnumSignalEnumeratedFlagValue(1, 0, OU_UINT64_BITS);
		
		if (sfTestFlags.QueryFlagsAllValues() != 1)
		{
			break;
		}
		
		sfTestFlags.EnumSignalEnumeratedFlagValue(1, OU_UINT64_BITS - 1, OU_UINT64_BITS);
		
		if (sfTestFlags.QueryFlagsAllValues() != (uint64ou)(OU_INT64_MIN + 1))
		{
			break;
		}
		
		sfTestFlags.EnumSignalEnumeratedFlagValue(1, 0, OU_UINT64_BITS);
		
		if (sfTestFlags.QueryFlagsAllValues() != (uint64ou)(OU_INT64_MIN + 1))
		{
			break;
		}
		
		sfTestFlags.EnumSignalEnumeratedFlagValue(1, OU_UINT64_BITS - 1, OU_UINT64_BITS);
		
		if (sfTestFlags.QueryFlagsAllValues() != (uint64ou)(OU_INT64_MIN + 1))
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags64_EnumDropEnumeratedFlagValue()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags64 sfTestFlags(OU_UINT64_MAX);
		
		sfTestFlags.EnumDropEnumeratedFlagValue(1, 0, OU_UINT64_BITS);
		
		if (sfTestFlags.QueryFlagsAllValues() != (OU_UINT64_MAX ^ 1))
		{
			break;
		}
		
		sfTestFlags.EnumDropEnumeratedFlagValue(1, OU_UINT64_BITS - 1, OU_UINT64_BITS);
		
		if (sfTestFlags.QueryFlagsAllValues() != (uint64ou)~(OU_INT64_MIN + 1))
		{
			break;
		}
		
		sfTestFlags.EnumDropEnumeratedFlagValue(1, 0, OU_UINT64_BITS);
		
		if (sfTestFlags.QueryFlagsAllValues() != (uint64ou)~(OU_INT64_MIN + 1))
		{
			break;
		}
		
		sfTestFlags.EnumDropEnumeratedFlagValue(1, OU_UINT64_BITS - 1, OU_UINT64_BITS);
		
		if (sfTestFlags.QueryFlagsAllValues() != (uint64ou)~(OU_INT64_MIN + 1))
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags64_EnumToggleEnumeratedFlagValue()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags64 sfTestFlags;
		
		bool bToggleFirstResult = sfTestFlags.EnumToggleEnumeratedFlagValue(1, 0, OU_UINT64_BITS);
		
		if (bToggleFirstResult || sfTestFlags.QueryFlagsAllValues() != 1)
		{
			break;
		}
		
		bool bToggleSecondResult = sfTestFlags.EnumToggleEnumeratedFlagValue(1, OU_UINT64_BITS - 1, OU_UINT64_BITS);
		
		if (bToggleSecondResult || sfTestFlags.QueryFlagsAllValues() != (uint64ou)(OU_INT64_MIN + 1))
		{
			break;
		}
		
		bool bToggleThirdResult = sfTestFlags.EnumToggleEnumeratedFlagValue(1, 0, OU_UINT64_BITS);
		
		if (!bToggleThirdResult || sfTestFlags.QueryFlagsAllValues() != (uint64ou)OU_INT64_MIN)
		{
			break;
		}
		
		bool bToggleFourthResult = sfTestFlags.EnumToggleEnumeratedFlagValue(1, OU_UINT64_BITS - 1, OU_UINT64_BITS);
		
		if (!bToggleFourthResult || sfTestFlags.QueryFlagsAllValues() != 0)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags64_EnumModifyEnumeratedFlagValue()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags64 sfTestFlags;
		
		bool bModifyFirstResult = sfTestFlags.EnumModifyEnumeratedFlagValue(1, 0, OU_UINT64_BITS, true);
		
		if (!bModifyFirstResult || sfTestFlags.QueryFlagsAllValues() != 1)
		{
			break;
		}
		
		bool bModifySecondResult = sfTestFlags.EnumModifyEnumeratedFlagValue(1, OU_UINT64_BITS - 1, OU_UINT64_BITS, true);
		
		if (!bModifySecondResult || sfTestFlags.QueryFlagsAllValues() != (uint64ou)(OU_INT64_MIN + 1))
		{
			break;
		}
		
		bool bModifyThirdResult = sfTestFlags.EnumModifyEnumeratedFlagValue(1, 0, OU_UINT64_BITS, true);
		
		if (bModifyThirdResult || sfTestFlags.QueryFlagsAllValues() != (uint64ou)(OU_INT64_MIN + 1))
		{
			break;
		}
		
		bool bModifyFourthResult = sfTestFlags.EnumModifyEnumeratedFlagValue(1, OU_UINT64_BITS - 1, OU_UINT64_BITS, true);
		
		if (bModifyFourthResult || sfTestFlags.QueryFlagsAllValues() != (uint64ou)(OU_INT64_MIN + 1))
		{
			break;
		}
		
		bool bModifyFifthResult = sfTestFlags.EnumModifyEnumeratedFlagValue(1, 0, OU_UINT64_BITS, false);
		
		if (!bModifyFifthResult || sfTestFlags.QueryFlagsAllValues() != (uint64ou)OU_INT64_MIN)
		{
			break;
		}
		
		bool bModifySixthResult = sfTestFlags.EnumModifyEnumeratedFlagValue(1, OU_UINT64_BITS - 1, OU_UINT64_BITS, false);
		
		if (!bModifySixthResult || sfTestFlags.QueryFlagsAllValues() != 0)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags64_EnumSignalFirstEnumeratedFlagValue()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags64 sfTestFlags;

		bool bFirstResult = sfTestFlags.EnumSignalFirstEnumeratedFlagValue(1, 0, OU_UINT64_BITS);

		if (!bFirstResult || sfTestFlags.QueryFlagsAllValues() != 1)
		{
			break;
		}
		
		bool bSecondResult = sfTestFlags.EnumSignalFirstEnumeratedFlagValue(1, 0, OU_UINT64_BITS);
		
		if (bSecondResult || sfTestFlags.QueryFlagsAllValues() != 1)
		{
			break;
		}
		
		bool bThirdResult = sfTestFlags.EnumSignalFirstEnumeratedFlagValue(2, 0, OU_UINT64_BITS - 1);
		
		if (!bThirdResult || sfTestFlags.QueryFlagsAllValues() != 3)
		{
			break;
		}
		
		bool bFourthResult = sfTestFlags.EnumSignalFirstEnumeratedFlagValue(1, OU_UINT64_BITS - 1, OU_UINT64_BITS);
		
		if (bFourthResult || sfTestFlags.QueryFlagsAllValues() != (uint64ou)(OU_INT64_MIN + 3))
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags64_EnumSignalLastEnumeratedFlagValue()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags64 sfTestFlags;
		
		bool bFirstResult = sfTestFlags.EnumSignalLastEnumeratedFlagValue(1, 0, 1);
		
		if (!bFirstResult || sfTestFlags.QueryFlagsAllValues() != 1)
		{
			break;
		}
		
		bool bSecondResult = sfTestFlags.EnumSignalLastEnumeratedFlagValue(1, 0, 1);
		
		if (bSecondResult || sfTestFlags.QueryFlagsAllValues() != 1)
		{
			break;
		}
		
		bool bThirdResult = sfTestFlags.EnumSignalLastEnumeratedFlagValue(1, 1, 2);
		
		if (!bThirdResult || sfTestFlags.QueryFlagsAllValues() != 3)
		{
			break;
		}
		
		bool bFourthResult = sfTestFlags.EnumSignalLastEnumeratedFlagValue(1, OU_UINT64_BITS - 1, OU_UINT64_BITS);
		
		if (bFourthResult || sfTestFlags.QueryFlagsAllValues() != (uint64ou)(OU_INT64_MIN + 3))
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags64_EnumGetEnumeratedFlagValue()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags64 sfTestFlags((uint64ou)(OU_INT64_MIN + 1));
		
		if (!sfTestFlags.EnumGetEnumeratedFlagValue(1, 0, OU_UINT64_BITS))
		{
			break;
		}
	
		if (sfTestFlags.EnumGetEnumeratedFlagValue(2, 0, OU_UINT64_BITS - 1))
		{
			break;
		}
		
		if (sfTestFlags.EnumGetEnumeratedFlagValue(1, 1, OU_UINT64_BITS - 1))
		{
			break;
		}
		
		if (!sfTestFlags.EnumGetEnumeratedFlagValue(1, OU_UINT64_BITS - 1, OU_UINT64_BITS))
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags64_EnumFindFirstEnumeratedFlag()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags64 sfTestFlags((uint64ou)(OU_INT64_MIN + 1));

		unsigned int uiFirstResult = sfTestFlags.EnumFindFirstEnumeratedFlag(1, OU_UINT64_BITS);
		if (uiFirstResult != 0)
		{
			break;
		}

		unsigned int uiSecondResult = sfTestFlags.EnumFindFirstEnumeratedFlag(2, OU_UINT64_BITS - 1);
		if (uiSecondResult != OU_UINT64_BITS - 2)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags64_EnumAllSignalEnumeratedFlags()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags64 sfTestFlags;
		
		sfTestFlags.EnumAllSignalEnumeratedFlags(1, 1);

		if (sfTestFlags.QueryFlagsAllValues() != 1)
		{
			break;
		}

		sfTestFlags.EnumAllSignalEnumeratedFlags(4, OU_UINT64_BITS - 2);

		if (sfTestFlags.QueryFlagsAllValues() != (uint64ou)(OU_UINT64_MAX ^ 2))
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags64_EnumAllDropEnumeratedFlags()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags64 sfTestFlags(OU_UINT64_MAX);
		
		sfTestFlags.EnumAllDropEnumeratedFlags(1, 1);
		
		if (sfTestFlags.QueryFlagsAllValues() != (uint64ou)(OU_UINT64_MAX ^ 1))
		{
			break;
		}
		
		sfTestFlags.EnumAllDropEnumeratedFlags(4, OU_UINT64_BITS - 2);
		
		if (sfTestFlags.QueryFlagsAllValues() != 2)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags64_EnumAllQueryEnumeratedFlags()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags64 sfTestFlags((uint64ou)(OU_INT64_MIN + 1));
		
		uint64ou uiFirstResult = sfTestFlags.EnumAllQueryEnumeratedFlags(1, OU_UINT64_BITS);
		if (uiFirstResult != (uint64ou)(OU_INT64_MIN + 1))
		{
			break;
		}
		
		uint64ou uiSecondResult = sfTestFlags.EnumAllQueryEnumeratedFlags(2, OU_UINT64_BITS - 1);
		if (uiSecondResult != (uint64ou)(OU_INT64_MIN))
		{
			break;
		}
		
		uint64ou uiThirdResult = sfTestFlags.EnumAllQueryEnumeratedFlags(2, OU_UINT64_BITS - 2);
		if (uiThirdResult != 0)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags64_EnumAnyGetEnumeratedFlagValue()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags64 sfTestFlags((uint64ou)(OU_INT64_MIN + 1));
		
		bool bFirstResult = sfTestFlags.EnumAnyGetEnumeratedFlagValue(1, OU_UINT64_BITS);
		if (!bFirstResult)
		{
			break;
		}
		
		bool bSecondResult = sfTestFlags.EnumAnyGetEnumeratedFlagValue(2, OU_UINT64_BITS - 1);
		if (!bSecondResult)
		{
			break;
		}
		
		bool bThirdResult = sfTestFlags.EnumAnyGetEnumeratedFlagValue(2, OU_UINT64_BITS - 2);
		if (bThirdResult)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags64_StoreFlagsEnumeratedValue()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags64 sfTestFlags;

		sfTestFlags.StoreFlagsEnumeratedValue(0x03, 1, 2);

		if (sfTestFlags.QueryFlagsAllValues() != (uint64ou)(2 << 1))
		{
			break;
		}
	
		sfTestFlags.StoreFlagsEnumeratedValue(0x03, OU_UINT64_BITS - 2, 3);
		
		if (sfTestFlags.QueryFlagsAllValues() != ((uint64ou)(2 << 1) | (uint64ou)(OU_INT64_MIN | (OU_INT64_MIN >> 1))))
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags64_RetrieveFlagsEnumeratedValue()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags64 sfTestFlags((uint64ou)(OU_INT64_MIN + 1));
		
		unsigned int uiFirstResult = sfTestFlags.RetrieveFlagsEnumeratedValue(0x3, 1);
		if (uiFirstResult != 0)
		{
			break;
		}
		
		unsigned int uiSecondResult = sfTestFlags.RetrieveFlagsEnumeratedValue(0x3, OU_UINT64_BITS - 2);
		if (uiSecondResult != 2)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}


enum EOUSIMPLEFLAGSFEATURE64
{
	OSF64__MIN,
		
	OSF64_CONSTRUCTORS = OSF64__MIN,
	OSF64_ASSIGNFLAGSALLVALUES,
	OSF64_QUERYFLAGSALLVALUES,
	OSF64_SETFLAGSMASKVALUE,
	OSF64_SIGNALFLAGSMASKVALUE,
	OSF64_DROPFLAGSMASKVALUE,
	OSF64_TOGGLESINGLEFLAGVALUE,
	OSF64_MODIFYSINGLEFLAGVALUE,
	OSF64_ASSIGNFLAGSBYMASK,
	OSF64_ALTERFLAGSBYMASK,
	OSF64_GETFLAGSMASKVALUE,
	OSF64_QUERYFLAGSBYMASK,
	OSF64_ONLYSIGNALSINGLEFLAGOUTOFMASK,
	OSF64_ENUMSETENUMERATEDFLAGVALUE,
	OSF64_ENUMSIGNALENUMERATEDFLAGVALUE,
	OSF64_ENUMDROPENUMERATEDFLAGVALUE,
	OSF64_ENUMTOGGLEENUMERATEDFLAGVALUE,
	OSF64_ENUMMODIFYENUMERATEDFLAGVALUE,
	OSF64_ENUMSIGNALFIRSTENUMERATEDFLAGVALUE,
	OSF64_ENUMSIGNALLASTENUMERATEDFLAGVALUE,
	OSF64_ENUMGETENUMERATEDFLAGVALUE,
	OSF64_ENUMFINDFIRSTENUMERATEDFLAG,
	OSF64_ENUMALLSIGNALENUMERATEDFLAGS,
	OSF64_ENUMALLDROPENUMERATEDFLAGS,
	OSF64_ENUMALLQUERYENUMERATEDFLAGS,
	OSF64_ENUMANYGETENUMERATEDFLAGVALUE,
	OSF64_STOREFLAGSENUMERATEDVALUE,
	OSF64_RETRIEVEFLAGSENUMERATEDVALUE,

	OSF64__MAX,
};

template<>
CFeatureTestProcedure const CEnumUnsortedElementArray<EOUSIMPLEFLAGSFEATURE64, OSF64__MAX, CFeatureTestProcedure>::m_aetElementArray[] =
{
	&TestSimpleFlags64_Constructors, // OSF64_CONSTRUCTORS
	&TestSimpleFlags64_AssignFlagsAllValues, // OSF64_ASSIGNFLAGSALLVALUES,
	&TestSimpleFlags64_QueryFlagsAllValues, // OSF64_QUERYFLAGSALLVALUES,
	&TestSimpleFlags64_SetFlagsMaskValue, // OSF64_SETFLAGSMASKVALUE,
	&TestSimpleFlags64_SignalFlagsMaskValue, // OSF64_SIGNALFLAGSMASKVALUE,
	&TestSimpleFlags64_DropFlagsMaskValue, // OSF64_DROPFLAGSMASKVALUE,
	&TestSimpleFlags64_ToggleSingleFlagValue, // OSF64_TOGGLESINGLEFLAGVALUE,
	&TestSimpleFlags64_ModifySingleFlagValue, // OSF64_MODIFYSINGLEFLAGVALUE,
	&TestSimpleFlags64_AssignFlagsByMask, // OSF64_ASSIGNFLAGSBYMASK,
	&TestSimpleFlags64_AlterFlagsByMask, // OSF64_ALTERFLAGSBYMASK,
	&TestSimpleFlags64_GetFlagsMaskValue, // OSF64_GETFLAGSMASKVALUE,
	&TestSimpleFlags64_QueryFlagsByMask, // OSF64_QUERYFLAGSBYMASK,
	&TestSimpleFlags64_OnlySignalSingleFlagOutOfMask, // OSF64_ONLYSIGNALSINGLEFLAGOUTOFMASK,
	&TestSimpleFlags64_EnumSetEnumeratedFlagValue, // OSF64_ENUMSETENUMERATEDFLAGVALUE,
	&TestSimpleFlags64_EnumSignalEnumeratedFlagValue, // OSF64_ENUMSIGNALENUMERATEDFLAGVALUE,
	&TestSimpleFlags64_EnumDropEnumeratedFlagValue, // OSF64_ENUMDROPENUMERATEDFLAGVALUE,
	&TestSimpleFlags64_EnumToggleEnumeratedFlagValue, // OSF64_ENUMTOGGLEENUMERATEDFLAGVALUE,
	&TestSimpleFlags64_EnumModifyEnumeratedFlagValue, // OSF64_ENUMMODIFYENUMERATEDFLAGVALUE,
	&TestSimpleFlags64_EnumSignalFirstEnumeratedFlagValue, // OSF64_ENUMSIGNALFIRSTENUMERATEDFLAGVALUE,
	&TestSimpleFlags64_EnumSignalLastEnumeratedFlagValue, // OSF64_ENUMSIGNALLASTENUMERATEDFLAGVALUE,
	&TestSimpleFlags64_EnumGetEnumeratedFlagValue, // OSF64_ENUMGETENUMERATEDFLAGVALUE,
	&TestSimpleFlags64_EnumFindFirstEnumeratedFlag, // OSF64_ENUMFINDFIRSTENUMERATEDFLAG,
	&TestSimpleFlags64_EnumAllSignalEnumeratedFlags, // OSF64_ENUMALLSIGNALENUMERATEDFLAGS,
	&TestSimpleFlags64_EnumAllDropEnumeratedFlags, // OSF64_ENUMALLDROPENUMERATEDFLAGS,
	&TestSimpleFlags64_EnumAllQueryEnumeratedFlags, // OSF64_ENUMALLQUERYENUMERATEDFLAGS,
	&TestSimpleFlags64_EnumAnyGetEnumeratedFlagValue, // OSF64_ENUMANYGETENUMERATEDFLAGVALUE,
	&TestSimpleFlags64_StoreFlagsEnumeratedValue, // OSF64_STOREFLAGSENUMERATEDVALUE,
	&TestSimpleFlags64_RetrieveFlagsEnumeratedValue, // OSF64_RETRIEVEFLAGSENUMERATEDVALUE,
};
static const CEnumUnsortedElementArray<EOUSIMPLEFLAGSFEATURE64, OSF64__MAX, CFeatureTestProcedure> g_afnSimpleFlags64FeatureTestProcedures;

template<>
const char *const CEnumUnsortedElementArray<EOUSIMPLEFLAGSFEATURE64, OSF64__MAX, const char *>::m_aetElementArray[] =
{
	"Constructors", // OSF64_CONSTRUCTORS
	"AssignFlagsAllValues", // OSF64_ASSIGNFLAGSALLVALUES,
	"QueryFlagsAllValues", // OSF64_QUERYFLAGSALLVALUES,
	"SetFlagsMaskValue", // OSF64_SETFLAGSMASKVALUE,
	"SignalFlagsMaskValue", // OSF64_SIGNALFLAGSMASKVALUE,
	"DropFlagsMaskValue", // OSF64_DROPFLAGSMASKVALUE,
	"ToggleSingleFlagValue", // OSF64_TOGGLESINGLEFLAGVALUE,
	"ModifySingleFlagValue", // OSF64_MODIFYSINGLEFLAGVALUE,
	"AssignFlagsByMask", // OSF64_ASSIGNFLAGSBYMASK,
	"AlterFlagsByMask", // OSF64_ALTERFLAGSBYMASK,
	"GetFlagsMaskValue", // OSF64_GETFLAGSMASKVALUE,
	"QueryFlagsByMask", // OSF64_QUERYFLAGSBYMASK,
	"OnlySignalSingleFlagOutOfMask", // OSF64_ONLYSIGNALSINGLEFLAGOUTOFMASK,
	"EnumSetEnumeratedFlagValue", // OSF64_ENUMSETENUMERATEDFLAGVALUE,
	"EnumSignalEnumeratedFlagValue", // OSF64_ENUMSIGNALENUMERATEDFLAGVALUE,
	"EnumDropEnumeratedFlagValue", // OSF64_ENUMDROPENUMERATEDFLAGVALUE,
	"EnumToggleEnumeratedFlagValue", // OSF64_ENUMTOGGLEENUMERATEDFLAGVALUE,
	"EnumModifyEnumeratedFlagValue", // OSF64_ENUMMODIFYENUMERATEDFLAGVALUE,
	"EnumSignalFirstEnumeratedFlagValue", // OSF64_ENUMSIGNALFIRSTENUMERATEDFLAGVALUE,
	"EnumSignalLastEnumeratedFlagValue", // OSF64_ENUMSIGNALLASTENUMERATEDFLAGVALUE,
	"EnumGetEnumeratedFlagValue", // OSF64_ENUMGETENUMERATEDFLAGVALUE,
	"EnumFindFirstEnumeratedFlag", // OSF64_ENUMFINDFIRSTENUMERATEDFLAG,
	"EnumAllSignalEnumeratedFlags", // OSF64_ENUMALLSIGNALENUMERATEDFLAGS,
	"EnumAllDropEnumeratedFlags", // OSF64_ENUMALLDROPENUMERATEDFLAGS,
	"EnumAllQueryEnumeratedFlags", // OSF64_ENUMALLQUERYENUMERATEDFLAGS,
	"EnumAnyGetEnumeratedFlagValue", // OSF64_ENUMANYGETENUMERATEDFLAGVALUE,
	"StoreFlagsEnumeratedValue", // OSF64_STOREFLAGSENUMERATEDVALUE,
	"RetrieveFlagsEnumeratedValue", // OSF64_RETRIEVEFLAGSENUMERATEDVALUE,
};
static const CEnumUnsortedElementArray<EOUSIMPLEFLAGSFEATURE64, OSF64__MAX, const char *> g_aszSimpleFlags64FeatureTestNames;


bool TestSimpleFlags64(unsigned int &nOutSuccessCount, unsigned int &nOutTestCount)
{
	return TestSubsystem(nOutSuccessCount, nOutTestCount, OSF64__MAX, g_aszSimpleFlags64FeatureTestNames.GetStoragePointer(), g_afnSimpleFlags64FeatureTestProcedures.GetStoragePointer());
}


//////////////////////////////////////////////////////////////////////////

typedef CSimpleFlags CSimpleFlags32;

const uint32ou g_uiTestValue32 = (uint32ou)0xA5A5A5A5;
const uint32ou g_uiTestMask32 = (uint32ou)0xC6C6C6C6;
const uint32ou g_uiTestBit32 = (uint32ou)OU_INT32_MIN;
const uint32ou g_uiTestAnotherBit32 = (uint32ou)((uint32ou)OU_INT32_MIN >> 1);


bool TestSimpleFlags32_Constructors()
{
	bool bResult = false;
	
	do
	{
		if (sizeof(CSimpleFlags32::value_type) != sizeof(uint32ou) || sizeof(CSimpleFlags32) != sizeof(uint32ou))
		{
			break;
		}

		CSimpleFlags32 sfEmptyFlags;

		if (sfEmptyFlags.QueryFlagsAllValues())
		{
			break;
		}

		CSimpleFlags32 sfFullFlags(OU_UINT32_MAX);
		
		if (sfFullFlags.QueryFlagsAllValues() != OU_UINT32_MAX)
		{
			break;
		}

		CSimpleFlags32 sfCopyOfFullFlags(sfFullFlags);

		if (sfCopyOfFullFlags.QueryFlagsAllValues() != OU_UINT32_MAX)
		{
			break;
		}
	
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags32_AssignFlagsAllValues()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags32 sfTestFlags;

		sfTestFlags.AssignFlagsAllValues(OU_UINT32_MAX);

		if (sfTestFlags.QueryFlagsAllValues() != OU_UINT32_MAX)
		{
			break;
		}

		sfTestFlags.AssignFlagsAllValues(0);

		if (sfTestFlags.QueryFlagsAllValues() != 0)
		{
			break;
		}
	
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags32_QueryFlagsAllValues()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags32 sfTestFlags(g_uiTestValue32);
		
		if (sfTestFlags.QueryFlagsAllValues() != g_uiTestValue32)
		{
			break;
		}

		// Double check to be sure ;-)
		if (sfTestFlags.QueryFlagsAllValues() != g_uiTestValue32)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags32_SetFlagsMaskValue()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags32 sfTestFlags(g_uiTestValue32);

		sfTestFlags.SetFlagsMaskValue(g_uiTestMask32, true);

		if (sfTestFlags.QueryFlagsAllValues() != (uint32ou)(g_uiTestValue32 | g_uiTestMask32))
		{
			break;
		}

		sfTestFlags.SetFlagsMaskValue(g_uiTestValue32, false);

		if (sfTestFlags.QueryFlagsAllValues() != (uint32ou)(~g_uiTestValue32 & g_uiTestMask32))
		{
			break;
		}
		

		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags32_SignalFlagsMaskValue()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags32 sfTestFlags(g_uiTestValue32);
		
		sfTestFlags.SignalFlagsMaskValue(g_uiTestMask32);
		
		if (sfTestFlags.QueryFlagsAllValues() != (uint32ou)(g_uiTestValue32 | g_uiTestMask32))
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags32_DropFlagsMaskValue()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags32 sfTestFlags(g_uiTestValue32);
		
		sfTestFlags.DropFlagsMaskValue(g_uiTestMask32);
		
		if (sfTestFlags.QueryFlagsAllValues() != (uint32ou)(g_uiTestValue32 & ~g_uiTestMask32))
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags32_ToggleSingleFlagValue()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags32 sfTestFlags(g_uiTestValue32);
		
		bool bPreviousValue = sfTestFlags.ToggleSingleFlagValue(g_uiTestBit32);
		
		if (bPreviousValue != ((g_uiTestValue32 & g_uiTestBit32) != 0) || sfTestFlags.QueryFlagsAllValues() != (uint32ou)(g_uiTestValue32 ^ g_uiTestBit32))
		{
			break;
		}

		bool bAnotherPreviousValue = sfTestFlags.ToggleSingleFlagValue(g_uiTestBit32);
		
		if (bAnotherPreviousValue == bPreviousValue || sfTestFlags.QueryFlagsAllValues() != g_uiTestValue32)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags32_ModifySingleFlagValue()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags32 sfTestFlags(g_uiTestValue32);
		
		bool bFirstModification = sfTestFlags.ModifySingleFlagValue(g_uiTestBit32, true);
		
		if (bFirstModification != ((g_uiTestValue32 & g_uiTestBit32) != g_uiTestBit32) || sfTestFlags.QueryFlagsAllValues() != (uint32ou)(g_uiTestValue32 | g_uiTestBit32))
		{
			break;
		}
		
		bool bAnotherModification = sfTestFlags.ModifySingleFlagValue(g_uiTestBit32, bFirstModification);
		
		if (bAnotherModification == bFirstModification || sfTestFlags.QueryFlagsAllValues() != (bFirstModification ? (uint32ou)(g_uiTestValue32 | g_uiTestBit32) : (uint32ou)(g_uiTestValue32 & ~g_uiTestBit32)))
		{
			break;
		}

		bool bYetAnotherModification = sfTestFlags.ModifySingleFlagValue(g_uiTestBit32, bAnotherModification);

		if (bYetAnotherModification != bAnotherModification || sfTestFlags.QueryFlagsAllValues() != (bAnotherModification ? (uint32ou)(g_uiTestValue32 | g_uiTestBit32) : (uint32ou)(g_uiTestValue32 & ~g_uiTestBit32)))
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags32_AssignFlagsByMask()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags32 sfTestFlags(g_uiTestValue32);

		uint32ou uiPreviousFlags = sfTestFlags.AssignFlagsByMask(g_uiTestMask32, g_uiTestMask32);

		const uint32ou uiNewFlags = (g_uiTestValue32 & ~g_uiTestMask32) | g_uiTestMask32;

		if (uiPreviousFlags != g_uiTestValue32 || sfTestFlags.QueryFlagsAllValues() != uiNewFlags)
		{
			break;
		}

		uint32ou uiAnotherPreviousFlags = sfTestFlags.AssignFlagsByMask(g_uiTestValue32, 0);

		const uint32ou uiAnotherNewFlags = uiNewFlags & ~g_uiTestValue32;

		if (uiAnotherPreviousFlags != uiNewFlags || sfTestFlags.QueryFlagsAllValues() != uiAnotherNewFlags)
		{
			break;
		}
	
		uint32ou uiYetAnotherPreviousFlags = sfTestFlags.AssignFlagsByMask(g_uiTestMask32, g_uiTestMask32 & g_uiTestValue32);
		OU_ASSERT((g_uiTestMask32 & g_uiTestValue32) != 0); // Test degeneration
		
		const uint32ou uiYetAnotherNewFlags = (uiAnotherNewFlags & ~g_uiTestMask32) | (g_uiTestMask32 & g_uiTestValue32);
		OU_ASSERT(uiYetAnotherNewFlags != OU_UINT32_MAX); // Test degeneration
		
		if (uiYetAnotherPreviousFlags != uiAnotherNewFlags || sfTestFlags.QueryFlagsAllValues() != uiYetAnotherNewFlags)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags32_AlterFlagsByMask()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags32 sfTestFlags(g_uiTestValue32);
		
		bool bWasModification = sfTestFlags.AlterFlagsByMask(g_uiTestMask32, g_uiTestMask32);
		
		const uint32ou uiNewFlags = (g_uiTestValue32 & ~g_uiTestMask32) | g_uiTestMask32;
		
		if (bWasModification != ((g_uiTestValue32 & g_uiTestMask32) != g_uiTestMask32) || sfTestFlags.QueryFlagsAllValues() != uiNewFlags)
		{
			break;
		}
		
		bool bWasAnotherModification = sfTestFlags.AlterFlagsByMask(g_uiTestValue32, 0);
		
		const uint32ou uiAnotherNewFlags = uiNewFlags & ~g_uiTestValue32;
		
		if (bWasAnotherModification != ((uiNewFlags & g_uiTestValue32) != 0) || sfTestFlags.QueryFlagsAllValues() != uiAnotherNewFlags)
		{
			break;
		}
		
		bool bWasAnotherModificationRepeated = sfTestFlags.AlterFlagsByMask(g_uiTestValue32, 0);
		
		if (bWasAnotherModificationRepeated || sfTestFlags.QueryFlagsAllValues() != uiAnotherNewFlags)
		{
			break;
		}
		
		bool bWasYetAnotherModification = sfTestFlags.AlterFlagsByMask(g_uiTestMask32, g_uiTestMask32 & g_uiTestValue32);
		OU_ASSERT((g_uiTestMask32 & g_uiTestValue32) != 0); // Test degeneration
		
		const uint32ou uiYetAnotherNewFlags = (uiAnotherNewFlags & ~g_uiTestMask32) | (g_uiTestMask32 & g_uiTestValue32);
		OU_ASSERT(uiYetAnotherNewFlags != OU_UINT32_MAX); // Test degeneration
		
		if (bWasYetAnotherModification != ((uiAnotherNewFlags & g_uiTestMask32) != (g_uiTestMask32 & g_uiTestValue32)) || sfTestFlags.QueryFlagsAllValues() != uiYetAnotherNewFlags)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags32_GetFlagsMaskValue()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags32 sfTestFlags(g_uiTestValue32);
		
		if (sfTestFlags.GetFlagsMaskValue(g_uiTestMask32) != ((g_uiTestValue32 & g_uiTestMask32) != 0))
		{
			break;
		}
		
		if (sfTestFlags.GetFlagsMaskValue(~g_uiTestValue32))
		{
			break;
		}
		
		if (!sfTestFlags.GetFlagsMaskValue(OU_UINT32_MAX))
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags32_QueryFlagsByMask()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags32 sfTestFlags(g_uiTestValue32);
		
		if (sfTestFlags.QueryFlagsByMask(g_uiTestMask32) != (uint32ou)(g_uiTestValue32 & g_uiTestMask32))
		{
			break;
		}
		
		if (sfTestFlags.QueryFlagsByMask(0))
		{
			break;
		}
		
		if (sfTestFlags.QueryFlagsByMask(OU_UINT32_MAX) != g_uiTestValue32)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags32_OnlySignalSingleFlagOutOfMask()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags32 sfTestFlags(g_uiTestValue32);
		OU_ASSERT(g_uiTestValue32 != 0); // Test degeneration
		
		if (sfTestFlags.OnlySignalSingleFlagOutOfMask(OU_UINT32_MAX, g_uiTestBit32))
		{
			break;
		}

		if (sfTestFlags.QueryFlagsAllValues() != g_uiTestValue32)
		{
			break;
		}
		
		sfTestFlags.AssignFlagsAllValues(0);

		if (!sfTestFlags.OnlySignalSingleFlagOutOfMask(g_uiTestBit32, g_uiTestBit32))
		{
			break;
		}
		
		if (sfTestFlags.QueryFlagsAllValues() != g_uiTestBit32)
		{
			break;
		}
		
		if (sfTestFlags.OnlySignalSingleFlagOutOfMask(g_uiTestBit32, g_uiTestBit32))
		{
			break;
		}
		
		if (sfTestFlags.QueryFlagsAllValues() != g_uiTestBit32)
		{
			break;
		}
		
		if (sfTestFlags.OnlySignalSingleFlagOutOfMask(OU_UINT32_MAX, g_uiTestAnotherBit32))
		{
			break;
		}
		
		if (sfTestFlags.QueryFlagsAllValues() != g_uiTestBit32)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags32_EnumSetEnumeratedFlagValue()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags32 sfTestFlags;
		
		sfTestFlags.EnumSetEnumeratedFlagValue(1, 0, OU_UINT32_BITS, true);

		if (sfTestFlags.QueryFlagsAllValues() != 1)
		{
			break;
		}
	
		sfTestFlags.EnumSetEnumeratedFlagValue(1, OU_UINT32_BITS - 1, OU_UINT32_BITS, true);
		
		if (sfTestFlags.QueryFlagsAllValues() != (uint32ou)(OU_INT32_MIN + 1))
		{
			break;
		}
		
		sfTestFlags.EnumSetEnumeratedFlagValue(1, 0, OU_UINT32_BITS, false);
		
		if (sfTestFlags.QueryFlagsAllValues() != (uint32ou)OU_INT32_MIN)
		{
			break;
		}
		
		sfTestFlags.EnumSetEnumeratedFlagValue(1, OU_UINT32_BITS - 1, OU_UINT32_BITS, false);
		
		if (sfTestFlags.QueryFlagsAllValues() != 0)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags32_EnumSignalEnumeratedFlagValue()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags32 sfTestFlags;
		
		sfTestFlags.EnumSignalEnumeratedFlagValue(1, 0, OU_UINT32_BITS);
		
		if (sfTestFlags.QueryFlagsAllValues() != 1)
		{
			break;
		}
		
		sfTestFlags.EnumSignalEnumeratedFlagValue(1, OU_UINT32_BITS - 1, OU_UINT32_BITS);
		
		if (sfTestFlags.QueryFlagsAllValues() != (uint32ou)(OU_INT32_MIN + 1))
		{
			break;
		}
		
		sfTestFlags.EnumSignalEnumeratedFlagValue(1, 0, OU_UINT32_BITS);
		
		if (sfTestFlags.QueryFlagsAllValues() != (uint32ou)(OU_INT32_MIN + 1))
		{
			break;
		}
		
		sfTestFlags.EnumSignalEnumeratedFlagValue(1, OU_UINT32_BITS - 1, OU_UINT32_BITS);
		
		if (sfTestFlags.QueryFlagsAllValues() != (uint32ou)(OU_INT32_MIN + 1))
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags32_EnumDropEnumeratedFlagValue()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags32 sfTestFlags(OU_UINT32_MAX);
		
		sfTestFlags.EnumDropEnumeratedFlagValue(1, 0, OU_UINT32_BITS);
		
		if (sfTestFlags.QueryFlagsAllValues() != (OU_UINT32_MAX ^ 1))
		{
			break;
		}
		
		sfTestFlags.EnumDropEnumeratedFlagValue(1, OU_UINT32_BITS - 1, OU_UINT32_BITS);
		
		if (sfTestFlags.QueryFlagsAllValues() != (uint32ou)~(OU_INT32_MIN + 1))
		{
			break;
		}
		
		sfTestFlags.EnumDropEnumeratedFlagValue(1, 0, OU_UINT32_BITS);
		
		if (sfTestFlags.QueryFlagsAllValues() != (uint32ou)~(OU_INT32_MIN + 1))
		{
			break;
		}
		
		sfTestFlags.EnumDropEnumeratedFlagValue(1, OU_UINT32_BITS - 1, OU_UINT32_BITS);
		
		if (sfTestFlags.QueryFlagsAllValues() != (uint32ou)~(OU_INT32_MIN + 1))
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags32_EnumToggleEnumeratedFlagValue()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags32 sfTestFlags;
		
		bool bToggleFirstResult = sfTestFlags.EnumToggleEnumeratedFlagValue(1, 0, OU_UINT32_BITS);
		
		if (bToggleFirstResult || sfTestFlags.QueryFlagsAllValues() != 1)
		{
			break;
		}
		
		bool bToggleSecondResult = sfTestFlags.EnumToggleEnumeratedFlagValue(1, OU_UINT32_BITS - 1, OU_UINT32_BITS);
		
		if (bToggleSecondResult || sfTestFlags.QueryFlagsAllValues() != (uint32ou)(OU_INT32_MIN + 1))
		{
			break;
		}
		
		bool bToggleThirdResult = sfTestFlags.EnumToggleEnumeratedFlagValue(1, 0, OU_UINT32_BITS);
		
		if (!bToggleThirdResult || sfTestFlags.QueryFlagsAllValues() != (uint32ou)OU_INT32_MIN)
		{
			break;
		}
		
		bool bToggleFourthResult = sfTestFlags.EnumToggleEnumeratedFlagValue(1, OU_UINT32_BITS - 1, OU_UINT32_BITS);
		
		if (!bToggleFourthResult || sfTestFlags.QueryFlagsAllValues() != 0)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags32_EnumModifyEnumeratedFlagValue()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags32 sfTestFlags;
		
		bool bModifyFirstResult = sfTestFlags.EnumModifyEnumeratedFlagValue(1, 0, OU_UINT32_BITS, true);
		
		if (!bModifyFirstResult || sfTestFlags.QueryFlagsAllValues() != 1)
		{
			break;
		}
		
		bool bModifySecondResult = sfTestFlags.EnumModifyEnumeratedFlagValue(1, OU_UINT32_BITS - 1, OU_UINT32_BITS, true);
		
		if (!bModifySecondResult || sfTestFlags.QueryFlagsAllValues() != (uint32ou)(OU_INT32_MIN + 1))
		{
			break;
		}
		
		bool bModifyThirdResult = sfTestFlags.EnumModifyEnumeratedFlagValue(1, 0, OU_UINT32_BITS, true);
		
		if (bModifyThirdResult || sfTestFlags.QueryFlagsAllValues() != (uint32ou)(OU_INT32_MIN + 1))
		{
			break;
		}
		
		bool bModifyFourthResult = sfTestFlags.EnumModifyEnumeratedFlagValue(1, OU_UINT32_BITS - 1, OU_UINT32_BITS, true);
		
		if (bModifyFourthResult || sfTestFlags.QueryFlagsAllValues() != (uint32ou)(OU_INT32_MIN + 1))
		{
			break;
		}
		
		bool bModifyFifthResult = sfTestFlags.EnumModifyEnumeratedFlagValue(1, 0, OU_UINT32_BITS, false);
		
		if (!bModifyFifthResult || sfTestFlags.QueryFlagsAllValues() != (uint32ou)OU_INT32_MIN)
		{
			break;
		}
		
		bool bModifySixthResult = sfTestFlags.EnumModifyEnumeratedFlagValue(1, OU_UINT32_BITS - 1, OU_UINT32_BITS, false);
		
		if (!bModifySixthResult || sfTestFlags.QueryFlagsAllValues() != 0)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags32_EnumSignalFirstEnumeratedFlagValue()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags32 sfTestFlags;

		bool bFirstResult = sfTestFlags.EnumSignalFirstEnumeratedFlagValue(1, 0, OU_UINT32_BITS);

		if (!bFirstResult || sfTestFlags.QueryFlagsAllValues() != 1)
		{
			break;
		}
		
		bool bSecondResult = sfTestFlags.EnumSignalFirstEnumeratedFlagValue(1, 0, OU_UINT32_BITS);
		
		if (bSecondResult || sfTestFlags.QueryFlagsAllValues() != 1)
		{
			break;
		}
		
		bool bThirdResult = sfTestFlags.EnumSignalFirstEnumeratedFlagValue(2, 0, OU_UINT32_BITS - 1);
		
		if (!bThirdResult || sfTestFlags.QueryFlagsAllValues() != 3)
		{
			break;
		}
		
		bool bFourthResult = sfTestFlags.EnumSignalFirstEnumeratedFlagValue(1, OU_UINT32_BITS - 1, OU_UINT32_BITS);
		
		if (bFourthResult || sfTestFlags.QueryFlagsAllValues() != (uint32ou)(OU_INT32_MIN + 3))
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags32_EnumSignalLastEnumeratedFlagValue()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags32 sfTestFlags;
		
		bool bFirstResult = sfTestFlags.EnumSignalLastEnumeratedFlagValue(1, 0, 1);
		
		if (!bFirstResult || sfTestFlags.QueryFlagsAllValues() != 1)
		{
			break;
		}
		
		bool bSecondResult = sfTestFlags.EnumSignalLastEnumeratedFlagValue(1, 0, 1);
		
		if (bSecondResult || sfTestFlags.QueryFlagsAllValues() != 1)
		{
			break;
		}
		
		bool bThirdResult = sfTestFlags.EnumSignalLastEnumeratedFlagValue(1, 1, 2);
		
		if (!bThirdResult || sfTestFlags.QueryFlagsAllValues() != 3)
		{
			break;
		}
		
		bool bFourthResult = sfTestFlags.EnumSignalLastEnumeratedFlagValue(1, OU_UINT32_BITS - 1, OU_UINT32_BITS);
		
		if (bFourthResult || sfTestFlags.QueryFlagsAllValues() != (uint32ou)(OU_INT32_MIN + 3))
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags32_EnumGetEnumeratedFlagValue()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags32 sfTestFlags((uint32ou)(OU_INT32_MIN + 1));
		
		if (!sfTestFlags.EnumGetEnumeratedFlagValue(1, 0, OU_UINT32_BITS))
		{
			break;
		}
	
		if (sfTestFlags.EnumGetEnumeratedFlagValue(2, 0, OU_UINT32_BITS - 1))
		{
			break;
		}
		
		if (sfTestFlags.EnumGetEnumeratedFlagValue(1, 1, OU_UINT32_BITS - 1))
		{
			break;
		}
		
		if (!sfTestFlags.EnumGetEnumeratedFlagValue(1, OU_UINT32_BITS - 1, OU_UINT32_BITS))
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags32_EnumFindFirstEnumeratedFlag()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags32 sfTestFlags((uint32ou)(OU_INT32_MIN + 1));

		unsigned int uiFirstResult = sfTestFlags.EnumFindFirstEnumeratedFlag(1, OU_UINT32_BITS);
		if (uiFirstResult != 0)
		{
			break;
		}

		unsigned int uiSecondResult = sfTestFlags.EnumFindFirstEnumeratedFlag(2, OU_UINT32_BITS - 1);
		if (uiSecondResult != OU_UINT32_BITS - 2)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags32_EnumAllSignalEnumeratedFlags()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags32 sfTestFlags;
		
		sfTestFlags.EnumAllSignalEnumeratedFlags(1, 1);

		if (sfTestFlags.QueryFlagsAllValues() != 1)
		{
			break;
		}

		sfTestFlags.EnumAllSignalEnumeratedFlags(4, OU_UINT32_BITS - 2);

		if (sfTestFlags.QueryFlagsAllValues() != (uint32ou)(OU_UINT32_MAX ^ 2))
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags32_EnumAllDropEnumeratedFlags()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags32 sfTestFlags(OU_UINT32_MAX);
		
		sfTestFlags.EnumAllDropEnumeratedFlags(1, 1);
		
		if (sfTestFlags.QueryFlagsAllValues() != (uint32ou)(OU_UINT32_MAX ^ 1))
		{
			break;
		}
		
		sfTestFlags.EnumAllDropEnumeratedFlags(4, OU_UINT32_BITS - 2);
		
		if (sfTestFlags.QueryFlagsAllValues() != 2)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags32_EnumAllQueryEnumeratedFlags()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags32 sfTestFlags((uint32ou)(OU_INT32_MIN + 1));
		
		uint32ou uiFirstResult = sfTestFlags.EnumAllQueryEnumeratedFlags(1, OU_UINT32_BITS);
		if (uiFirstResult != (uint32ou)(OU_INT32_MIN + 1))
		{
			break;
		}
		
		uint32ou uiSecondResult = sfTestFlags.EnumAllQueryEnumeratedFlags(2, OU_UINT32_BITS - 1);
		if (uiSecondResult != (uint32ou)(OU_INT32_MIN))
		{
			break;
		}
		
		uint32ou uiThirdResult = sfTestFlags.EnumAllQueryEnumeratedFlags(2, OU_UINT32_BITS - 2);
		if (uiThirdResult != 0)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags32_EnumAnyGetEnumeratedFlagValue()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags32 sfTestFlags((uint32ou)(OU_INT32_MIN + 1));
		
		bool bFirstResult = sfTestFlags.EnumAnyGetEnumeratedFlagValue(1, OU_UINT32_BITS);
		if (!bFirstResult)
		{
			break;
		}
		
		bool bSecondResult = sfTestFlags.EnumAnyGetEnumeratedFlagValue(2, OU_UINT32_BITS - 1);
		if (!bSecondResult)
		{
			break;
		}
		
		bool bThirdResult = sfTestFlags.EnumAnyGetEnumeratedFlagValue(2, OU_UINT32_BITS - 2);
		if (bThirdResult)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags32_StoreFlagsEnumeratedValue()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags32 sfTestFlags;

		sfTestFlags.StoreFlagsEnumeratedValue(0x03, 1, 2);

		if (sfTestFlags.QueryFlagsAllValues() != (uint32ou)(2 << 1))
		{
			break;
		}
	
		sfTestFlags.StoreFlagsEnumeratedValue(0x03, OU_UINT32_BITS - 2, 3);
		
		if (sfTestFlags.QueryFlagsAllValues() != ((uint32ou)(2 << 1) | (uint32ou)(OU_INT32_MIN | (OU_INT32_MIN >> 1))))
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags32_RetrieveFlagsEnumeratedValue()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags32 sfTestFlags((uint32ou)(OU_INT32_MIN + 1));
		
		unsigned int uiFirstResult = sfTestFlags.RetrieveFlagsEnumeratedValue(0x3, 1);
		if (uiFirstResult != 0)
		{
			break;
		}
		
		unsigned int uiSecondResult = sfTestFlags.RetrieveFlagsEnumeratedValue(0x3, OU_UINT32_BITS - 2);
		if (uiSecondResult != 2)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}


enum EOUSIMPLEFLAGSFEATURE32
{
	OSF32__MIN,
		
	OSF32_CONSTRUCTORS = OSF32__MIN,
	OSF32_ASSIGNFLAGSALLVALUES,
	OSF32_QUERYFLAGSALLVALUES,
	OSF32_SETFLAGSMASKVALUE,
	OSF32_SIGNALFLAGSMASKVALUE,
	OSF32_DROPFLAGSMASKVALUE,
	OSF32_TOGGLESINGLEFLAGVALUE,
	OSF32_MODIFYSINGLEFLAGVALUE,
	OSF32_ASSIGNFLAGSBYMASK,
	OSF32_ALTERFLAGSBYMASK,
	OSF32_GETFLAGSMASKVALUE,
	OSF32_QUERYFLAGSBYMASK,
	OSF32_ONLYSIGNALSINGLEFLAGOUTOFMASK,
	OSF32_ENUMSETENUMERATEDFLAGVALUE,
	OSF32_ENUMSIGNALENUMERATEDFLAGVALUE,
	OSF32_ENUMDROPENUMERATEDFLAGVALUE,
	OSF32_ENUMTOGGLEENUMERATEDFLAGVALUE,
	OSF32_ENUMMODIFYENUMERATEDFLAGVALUE,
	OSF32_ENUMSIGNALFIRSTENUMERATEDFLAGVALUE,
	OSF32_ENUMSIGNALLASTENUMERATEDFLAGVALUE,
	OSF32_ENUMGETENUMERATEDFLAGVALUE,
	OSF32_ENUMFINDFIRSTENUMERATEDFLAG,
	OSF32_ENUMALLSIGNALENUMERATEDFLAGS,
	OSF32_ENUMALLDROPENUMERATEDFLAGS,
	OSF32_ENUMALLQUERYENUMERATEDFLAGS,
	OSF32_ENUMANYGETENUMERATEDFLAGVALUE,
	OSF32_STOREFLAGSENUMERATEDVALUE,
	OSF32_RETRIEVEFLAGSENUMERATEDVALUE,

	OSF32__MAX,
};

template<>
CFeatureTestProcedure const CEnumUnsortedElementArray<EOUSIMPLEFLAGSFEATURE32, OSF32__MAX, CFeatureTestProcedure>::m_aetElementArray[] =
{
	&TestSimpleFlags32_Constructors, // OSF32_CONSTRUCTORS
	&TestSimpleFlags32_AssignFlagsAllValues, // OSF32_ASSIGNFLAGSALLVALUES,
	&TestSimpleFlags32_QueryFlagsAllValues, // OSF32_QUERYFLAGSALLVALUES,
	&TestSimpleFlags32_SetFlagsMaskValue, // OSF32_SETFLAGSMASKVALUE,
	&TestSimpleFlags32_SignalFlagsMaskValue, // OSF32_SIGNALFLAGSMASKVALUE,
	&TestSimpleFlags32_DropFlagsMaskValue, // OSF32_DROPFLAGSMASKVALUE,
	&TestSimpleFlags32_ToggleSingleFlagValue, // OSF32_TOGGLESINGLEFLAGVALUE,
	&TestSimpleFlags32_ModifySingleFlagValue, // OSF32_MODIFYSINGLEFLAGVALUE,
	&TestSimpleFlags32_AssignFlagsByMask, // OSF32_ASSIGNFLAGSBYMASK,
	&TestSimpleFlags32_AlterFlagsByMask, // OSF32_ALTERFLAGSBYMASK,
	&TestSimpleFlags32_GetFlagsMaskValue, // OSF32_GETFLAGSMASKVALUE,
	&TestSimpleFlags32_QueryFlagsByMask, // OSF32_QUERYFLAGSBYMASK,
	&TestSimpleFlags32_OnlySignalSingleFlagOutOfMask, // OSF32_ONLYSIGNALSINGLEFLAGOUTOFMASK,
	&TestSimpleFlags32_EnumSetEnumeratedFlagValue, // OSF32_ENUMSETENUMERATEDFLAGVALUE,
	&TestSimpleFlags32_EnumSignalEnumeratedFlagValue, // OSF32_ENUMSIGNALENUMERATEDFLAGVALUE,
	&TestSimpleFlags32_EnumDropEnumeratedFlagValue, // OSF32_ENUMDROPENUMERATEDFLAGVALUE,
	&TestSimpleFlags32_EnumToggleEnumeratedFlagValue, // OSF32_ENUMTOGGLEENUMERATEDFLAGVALUE,
	&TestSimpleFlags32_EnumModifyEnumeratedFlagValue, // OSF32_ENUMMODIFYENUMERATEDFLAGVALUE,
	&TestSimpleFlags32_EnumSignalFirstEnumeratedFlagValue, // OSF32_ENUMSIGNALFIRSTENUMERATEDFLAGVALUE,
	&TestSimpleFlags32_EnumSignalLastEnumeratedFlagValue, // OSF32_ENUMSIGNALLASTENUMERATEDFLAGVALUE,
	&TestSimpleFlags32_EnumGetEnumeratedFlagValue, // OSF32_ENUMGETENUMERATEDFLAGVALUE,
	&TestSimpleFlags32_EnumFindFirstEnumeratedFlag, // OSF32_ENUMFINDFIRSTENUMERATEDFLAG,
	&TestSimpleFlags32_EnumAllSignalEnumeratedFlags, // OSF32_ENUMALLSIGNALENUMERATEDFLAGS,
	&TestSimpleFlags32_EnumAllDropEnumeratedFlags, // OSF32_ENUMALLDROPENUMERATEDFLAGS,
	&TestSimpleFlags32_EnumAllQueryEnumeratedFlags, // OSF32_ENUMALLQUERYENUMERATEDFLAGS,
	&TestSimpleFlags32_EnumAnyGetEnumeratedFlagValue, // OSF32_ENUMANYGETENUMERATEDFLAGVALUE,
	&TestSimpleFlags32_StoreFlagsEnumeratedValue, // OSF32_STOREFLAGSENUMERATEDVALUE,
	&TestSimpleFlags32_RetrieveFlagsEnumeratedValue, // OSF32_RETRIEVEFLAGSENUMERATEDVALUE,
};
static const CEnumUnsortedElementArray<EOUSIMPLEFLAGSFEATURE32, OSF32__MAX, CFeatureTestProcedure> g_afnSimpleFlags32FeatureTestProcedures;

template<>
const char *const CEnumUnsortedElementArray<EOUSIMPLEFLAGSFEATURE32, OSF32__MAX, const char *>::m_aetElementArray[] =
{
	"Constructors", // OSF32_CONSTRUCTORS
	"AssignFlagsAllValues", // OSF32_ASSIGNFLAGSALLVALUES,
	"QueryFlagsAllValues", // OSF32_QUERYFLAGSALLVALUES,
	"SetFlagsMaskValue", // OSF32_SETFLAGSMASKVALUE,
	"SignalFlagsMaskValue", // OSF32_SIGNALFLAGSMASKVALUE,
	"DropFlagsMaskValue", // OSF32_DROPFLAGSMASKVALUE,
	"ToggleSingleFlagValue", // OSF32_TOGGLESINGLEFLAGVALUE,
	"ModifySingleFlagValue", // OSF32_MODIFYSINGLEFLAGVALUE,
	"AssignFlagsByMask", // OSF32_ASSIGNFLAGSBYMASK,
	"AlterFlagsByMask", // OSF32_ALTERFLAGSBYMASK,
	"GetFlagsMaskValue", // OSF32_GETFLAGSMASKVALUE,
	"QueryFlagsByMask", // OSF32_QUERYFLAGSBYMASK,
	"OnlySignalSingleFlagOutOfMask", // OSF32_ONLYSIGNALSINGLEFLAGOUTOFMASK,
	"EnumSetEnumeratedFlagValue", // OSF32_ENUMSETENUMERATEDFLAGVALUE,
	"EnumSignalEnumeratedFlagValue", // OSF32_ENUMSIGNALENUMERATEDFLAGVALUE,
	"EnumDropEnumeratedFlagValue", // OSF32_ENUMDROPENUMERATEDFLAGVALUE,
	"EnumToggleEnumeratedFlagValue", // OSF32_ENUMTOGGLEENUMERATEDFLAGVALUE,
	"EnumModifyEnumeratedFlagValue", // OSF32_ENUMMODIFYENUMERATEDFLAGVALUE,
	"EnumSignalFirstEnumeratedFlagValue", // OSF32_ENUMSIGNALFIRSTENUMERATEDFLAGVALUE,
	"EnumSignalLastEnumeratedFlagValue", // OSF32_ENUMSIGNALLASTENUMERATEDFLAGVALUE,
	"EnumGetEnumeratedFlagValue", // OSF32_ENUMGETENUMERATEDFLAGVALUE,
	"EnumFindFirstEnumeratedFlag", // OSF32_ENUMFINDFIRSTENUMERATEDFLAG,
	"EnumAllSignalEnumeratedFlags", // OSF32_ENUMALLSIGNALENUMERATEDFLAGS,
	"EnumAllDropEnumeratedFlags", // OSF32_ENUMALLDROPENUMERATEDFLAGS,
	"EnumAllQueryEnumeratedFlags", // OSF32_ENUMALLQUERYENUMERATEDFLAGS,
	"EnumAnyGetEnumeratedFlagValue", // OSF32_ENUMANYGETENUMERATEDFLAGVALUE,
	"StoreFlagsEnumeratedValue", // OSF32_STOREFLAGSENUMERATEDVALUE,
	"RetrieveFlagsEnumeratedValue", // OSF32_RETRIEVEFLAGSENUMERATEDVALUE,
};
static const CEnumUnsortedElementArray<EOUSIMPLEFLAGSFEATURE32, OSF32__MAX, const char *> g_aszSimpleFlags32FeatureTestNames;


bool TestSimpleFlags32(unsigned int &nOutSuccessCount, unsigned int &nOutTestCount)
{
	return TestSubsystem(nOutSuccessCount, nOutTestCount, OSF32__MAX, g_aszSimpleFlags32FeatureTestNames.GetStoragePointer(), g_afnSimpleFlags32FeatureTestProcedures.GetStoragePointer());
}


//////////////////////////////////////////////////////////////////////////

typedef CSimpleFlagsTemplate<uint16ou> CSimpleFlags16;

const uint16ou g_uiTestValue16 = (uint16ou)0xA5A5;
const uint16ou g_uiTestMask16 = (uint16ou)0xC6C6;
const uint16ou g_uiTestBit16 = (uint16ou)OU_INT16_MIN;
const uint16ou g_uiTestAnotherBit16 = (uint16ou)((uint16ou)OU_INT16_MIN >> 1);


bool TestSimpleFlags16_Constructors()
{
	bool bResult = false;
	
	do
	{
		if (sizeof(CSimpleFlags16::value_type) != sizeof(uint16ou) || sizeof(CSimpleFlags16) != sizeof(uint16ou))
		{
			break;
		}

		CSimpleFlags16 sfEmptyFlags;

		if (sfEmptyFlags.QueryFlagsAllValues())
		{
			break;
		}

		CSimpleFlags16 sfFullFlags(OU_UINT16_MAX);
		
		if (sfFullFlags.QueryFlagsAllValues() != OU_UINT16_MAX)
		{
			break;
		}

		CSimpleFlags16 sfCopyOfFullFlags(sfFullFlags);

		if (sfCopyOfFullFlags.QueryFlagsAllValues() != OU_UINT16_MAX)
		{
			break;
		}
	
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags16_AssignFlagsAllValues()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags16 sfTestFlags;

		sfTestFlags.AssignFlagsAllValues(OU_UINT16_MAX);

		if (sfTestFlags.QueryFlagsAllValues() != OU_UINT16_MAX)
		{
			break;
		}

		sfTestFlags.AssignFlagsAllValues(0);

		if (sfTestFlags.QueryFlagsAllValues() != 0)
		{
			break;
		}
	
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags16_QueryFlagsAllValues()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags16 sfTestFlags(g_uiTestValue16);
		
		if (sfTestFlags.QueryFlagsAllValues() != g_uiTestValue16)
		{
			break;
		}

		// Double check to be sure ;-)
		if (sfTestFlags.QueryFlagsAllValues() != g_uiTestValue16)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags16_SetFlagsMaskValue()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags16 sfTestFlags(g_uiTestValue16);

		sfTestFlags.SetFlagsMaskValue(g_uiTestMask16, true);

		if (sfTestFlags.QueryFlagsAllValues() != (uint16ou)(g_uiTestValue16 | g_uiTestMask16))
		{
			break;
		}

		sfTestFlags.SetFlagsMaskValue(g_uiTestValue16, false);

		if (sfTestFlags.QueryFlagsAllValues() != (uint16ou)(~g_uiTestValue16 & g_uiTestMask16))
		{
			break;
		}
		

		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags16_SignalFlagsMaskValue()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags16 sfTestFlags(g_uiTestValue16);
		
		sfTestFlags.SignalFlagsMaskValue(g_uiTestMask16);
		
		if (sfTestFlags.QueryFlagsAllValues() != (uint16ou)(g_uiTestValue16 | g_uiTestMask16))
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags16_DropFlagsMaskValue()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags16 sfTestFlags(g_uiTestValue16);
		
		sfTestFlags.DropFlagsMaskValue(g_uiTestMask16);
		
		if (sfTestFlags.QueryFlagsAllValues() != (uint16ou)(g_uiTestValue16 & ~g_uiTestMask16))
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags16_ToggleSingleFlagValue()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags16 sfTestFlags(g_uiTestValue16);
		
		bool bPreviousValue = sfTestFlags.ToggleSingleFlagValue(g_uiTestBit16);
		
		if (bPreviousValue != ((g_uiTestValue16 & g_uiTestBit16) != 0) || sfTestFlags.QueryFlagsAllValues() != (uint16ou)(g_uiTestValue16 ^ g_uiTestBit16))
		{
			break;
		}

		bool bAnotherPreviousValue = sfTestFlags.ToggleSingleFlagValue(g_uiTestBit16);
		
		if (bAnotherPreviousValue == bPreviousValue || sfTestFlags.QueryFlagsAllValues() != g_uiTestValue16)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags16_ModifySingleFlagValue()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags16 sfTestFlags(g_uiTestValue16);
		
		bool bFirstModification = sfTestFlags.ModifySingleFlagValue(g_uiTestBit16, true);
		
		if (bFirstModification != ((g_uiTestValue16 & g_uiTestBit16) != g_uiTestBit16) || sfTestFlags.QueryFlagsAllValues() != (uint16ou)(g_uiTestValue16 | g_uiTestBit16))
		{
			break;
		}
		
		bool bAnotherModification = sfTestFlags.ModifySingleFlagValue(g_uiTestBit16, bFirstModification);
		
		if (bAnotherModification == bFirstModification || sfTestFlags.QueryFlagsAllValues() != (bFirstModification ? (uint16ou)(g_uiTestValue16 | g_uiTestBit16) : (uint16ou)(g_uiTestValue16 & ~g_uiTestBit16)))
		{
			break;
		}

		bool bYetAnotherModification = sfTestFlags.ModifySingleFlagValue(g_uiTestBit16, bAnotherModification);

		if (bYetAnotherModification != bAnotherModification || sfTestFlags.QueryFlagsAllValues() != (bAnotherModification ? (uint16ou)(g_uiTestValue16 | g_uiTestBit16) : (uint16ou)(g_uiTestValue16 & ~g_uiTestBit16)))
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags16_AssignFlagsByMask()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags16 sfTestFlags(g_uiTestValue16);

		uint16ou uiPreviousFlags = sfTestFlags.AssignFlagsByMask(g_uiTestMask16, g_uiTestMask16);

		const uint16ou uiNewFlags = (g_uiTestValue16 & ~g_uiTestMask16) | g_uiTestMask16;

		if (uiPreviousFlags != g_uiTestValue16 || sfTestFlags.QueryFlagsAllValues() != uiNewFlags)
		{
			break;
		}

		uint16ou uiAnotherPreviousFlags = sfTestFlags.AssignFlagsByMask(g_uiTestValue16, 0);

		const uint16ou uiAnotherNewFlags = uiNewFlags & ~g_uiTestValue16;

		if (uiAnotherPreviousFlags != uiNewFlags || sfTestFlags.QueryFlagsAllValues() != uiAnotherNewFlags)
		{
			break;
		}
	
		uint16ou uiYetAnotherPreviousFlags = sfTestFlags.AssignFlagsByMask(g_uiTestMask16, g_uiTestMask16 & g_uiTestValue16);
		OU_ASSERT((g_uiTestMask16 & g_uiTestValue16) != 0); // Test degeneration
		
		const uint16ou uiYetAnotherNewFlags = (uiAnotherNewFlags & ~g_uiTestMask16) | (g_uiTestMask16 & g_uiTestValue16);
		OU_ASSERT(uiYetAnotherNewFlags != OU_UINT16_MAX); // Test degeneration
		
		if (uiYetAnotherPreviousFlags != uiAnotherNewFlags || sfTestFlags.QueryFlagsAllValues() != uiYetAnotherNewFlags)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags16_AlterFlagsByMask()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags16 sfTestFlags(g_uiTestValue16);
		
		bool bWasModification = sfTestFlags.AlterFlagsByMask(g_uiTestMask16, g_uiTestMask16);
		
		const uint16ou uiNewFlags = (g_uiTestValue16 & ~g_uiTestMask16) | g_uiTestMask16;
		
		if (bWasModification != ((g_uiTestValue16 & g_uiTestMask16) != g_uiTestMask16) || sfTestFlags.QueryFlagsAllValues() != uiNewFlags)
		{
			break;
		}
		
		bool bWasAnotherModification = sfTestFlags.AlterFlagsByMask(g_uiTestValue16, 0);
		
		const uint16ou uiAnotherNewFlags = uiNewFlags & ~g_uiTestValue16;
		
		if (bWasAnotherModification != ((uiNewFlags & g_uiTestValue16) != 0) || sfTestFlags.QueryFlagsAllValues() != uiAnotherNewFlags)
		{
			break;
		}
		
		bool bWasAnotherModificationRepeated = sfTestFlags.AlterFlagsByMask(g_uiTestValue16, 0);
		
		if (bWasAnotherModificationRepeated || sfTestFlags.QueryFlagsAllValues() != uiAnotherNewFlags)
		{
			break;
		}
		
		bool bWasYetAnotherModification = sfTestFlags.AlterFlagsByMask(g_uiTestMask16, g_uiTestMask16 & g_uiTestValue16);
		OU_ASSERT((g_uiTestMask16 & g_uiTestValue16) != 0); // Test degeneration
		
		const uint16ou uiYetAnotherNewFlags = (uiAnotherNewFlags & ~g_uiTestMask16) | (g_uiTestMask16 & g_uiTestValue16);
		OU_ASSERT(uiYetAnotherNewFlags != OU_UINT16_MAX); // Test degeneration
		
		if (bWasYetAnotherModification != ((uiAnotherNewFlags & g_uiTestMask16) != (g_uiTestMask16 & g_uiTestValue16)) || sfTestFlags.QueryFlagsAllValues() != uiYetAnotherNewFlags)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags16_GetFlagsMaskValue()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags16 sfTestFlags(g_uiTestValue16);
		
		if (sfTestFlags.GetFlagsMaskValue(g_uiTestMask16) != ((g_uiTestValue16 & g_uiTestMask16) != 0))
		{
			break;
		}
		
		if (sfTestFlags.GetFlagsMaskValue((uint16ou)(~g_uiTestValue16)))
		{
			break;
		}
		
		if (!sfTestFlags.GetFlagsMaskValue(OU_UINT16_MAX))
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags16_QueryFlagsByMask()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags16 sfTestFlags(g_uiTestValue16);
		
		if (sfTestFlags.QueryFlagsByMask(g_uiTestMask16) != (uint16ou)(g_uiTestValue16 & g_uiTestMask16))
		{
			break;
		}
		
		if (sfTestFlags.QueryFlagsByMask(0))
		{
			break;
		}
		
		if (sfTestFlags.QueryFlagsByMask(OU_UINT16_MAX) != g_uiTestValue16)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags16_OnlySignalSingleFlagOutOfMask()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags16 sfTestFlags(g_uiTestValue16);
		OU_ASSERT(g_uiTestValue16 != 0); // Test degeneration
		
		if (sfTestFlags.OnlySignalSingleFlagOutOfMask(OU_UINT16_MAX, g_uiTestBit16))
		{
			break;
		}

		if (sfTestFlags.QueryFlagsAllValues() != g_uiTestValue16)
		{
			break;
		}
		
		sfTestFlags.AssignFlagsAllValues(0);

		if (!sfTestFlags.OnlySignalSingleFlagOutOfMask(g_uiTestBit16, g_uiTestBit16))
		{
			break;
		}
		
		if (sfTestFlags.QueryFlagsAllValues() != g_uiTestBit16)
		{
			break;
		}
		
		if (sfTestFlags.OnlySignalSingleFlagOutOfMask(g_uiTestBit16, g_uiTestBit16))
		{
			break;
		}
		
		if (sfTestFlags.QueryFlagsAllValues() != g_uiTestBit16)
		{
			break;
		}
		
		if (sfTestFlags.OnlySignalSingleFlagOutOfMask(OU_UINT16_MAX, g_uiTestAnotherBit16))
		{
			break;
		}
		
		if (sfTestFlags.QueryFlagsAllValues() != g_uiTestBit16)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags16_EnumSetEnumeratedFlagValue()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags16 sfTestFlags;
		
		sfTestFlags.EnumSetEnumeratedFlagValue(1, 0, OU_UINT16_BITS, true);

		if (sfTestFlags.QueryFlagsAllValues() != 1)
		{
			break;
		}
	
		sfTestFlags.EnumSetEnumeratedFlagValue(1, OU_UINT16_BITS - 1, OU_UINT16_BITS, true);
		
		if (sfTestFlags.QueryFlagsAllValues() != (uint16ou)(OU_INT16_MIN + 1))
		{
			break;
		}
		
		sfTestFlags.EnumSetEnumeratedFlagValue(1, 0, OU_UINT16_BITS, false);
		
		if (sfTestFlags.QueryFlagsAllValues() != (uint16ou)OU_INT16_MIN)
		{
			break;
		}
		
		sfTestFlags.EnumSetEnumeratedFlagValue(1, OU_UINT16_BITS - 1, OU_UINT16_BITS, false);
		
		if (sfTestFlags.QueryFlagsAllValues() != 0)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags16_EnumSignalEnumeratedFlagValue()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags16 sfTestFlags;
		
		sfTestFlags.EnumSignalEnumeratedFlagValue(1, 0, OU_UINT16_BITS);
		
		if (sfTestFlags.QueryFlagsAllValues() != 1)
		{
			break;
		}
		
		sfTestFlags.EnumSignalEnumeratedFlagValue(1, OU_UINT16_BITS - 1, OU_UINT16_BITS);
		
		if (sfTestFlags.QueryFlagsAllValues() != (uint16ou)(OU_INT16_MIN + 1))
		{
			break;
		}
		
		sfTestFlags.EnumSignalEnumeratedFlagValue(1, 0, OU_UINT16_BITS);
		
		if (sfTestFlags.QueryFlagsAllValues() != (uint16ou)(OU_INT16_MIN + 1))
		{
			break;
		}
		
		sfTestFlags.EnumSignalEnumeratedFlagValue(1, OU_UINT16_BITS - 1, OU_UINT16_BITS);
		
		if (sfTestFlags.QueryFlagsAllValues() != (uint16ou)(OU_INT16_MIN + 1))
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags16_EnumDropEnumeratedFlagValue()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags16 sfTestFlags(OU_UINT16_MAX);
		
		sfTestFlags.EnumDropEnumeratedFlagValue(1, 0, OU_UINT16_BITS);
		
		if (sfTestFlags.QueryFlagsAllValues() != (OU_UINT16_MAX ^ 1))
		{
			break;
		}
		
		sfTestFlags.EnumDropEnumeratedFlagValue(1, OU_UINT16_BITS - 1, OU_UINT16_BITS);
		
		if (sfTestFlags.QueryFlagsAllValues() != (uint16ou)~(OU_INT16_MIN + 1))
		{
			break;
		}
		
		sfTestFlags.EnumDropEnumeratedFlagValue(1, 0, OU_UINT16_BITS);
		
		if (sfTestFlags.QueryFlagsAllValues() != (uint16ou)~(OU_INT16_MIN + 1))
		{
			break;
		}
		
		sfTestFlags.EnumDropEnumeratedFlagValue(1, OU_UINT16_BITS - 1, OU_UINT16_BITS);
		
		if (sfTestFlags.QueryFlagsAllValues() != (uint16ou)~(OU_INT16_MIN + 1))
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags16_EnumToggleEnumeratedFlagValue()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags16 sfTestFlags;
		
		bool bToggleFirstResult = sfTestFlags.EnumToggleEnumeratedFlagValue(1, 0, OU_UINT16_BITS);
		
		if (bToggleFirstResult || sfTestFlags.QueryFlagsAllValues() != 1)
		{
			break;
		}
		
		bool bToggleSecondResult = sfTestFlags.EnumToggleEnumeratedFlagValue(1, OU_UINT16_BITS - 1, OU_UINT16_BITS);
		
		if (bToggleSecondResult || sfTestFlags.QueryFlagsAllValues() != (uint16ou)(OU_INT16_MIN + 1))
		{
			break;
		}
		
		bool bToggleThirdResult = sfTestFlags.EnumToggleEnumeratedFlagValue(1, 0, OU_UINT16_BITS);
		
		if (!bToggleThirdResult || sfTestFlags.QueryFlagsAllValues() != (uint16ou)OU_INT16_MIN)
		{
			break;
		}
		
		bool bToggleFourthResult = sfTestFlags.EnumToggleEnumeratedFlagValue(1, OU_UINT16_BITS - 1, OU_UINT16_BITS);
		
		if (!bToggleFourthResult || sfTestFlags.QueryFlagsAllValues() != 0)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags16_EnumModifyEnumeratedFlagValue()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags16 sfTestFlags;
		
		bool bModifyFirstResult = sfTestFlags.EnumModifyEnumeratedFlagValue(1, 0, OU_UINT16_BITS, true);
		
		if (!bModifyFirstResult || sfTestFlags.QueryFlagsAllValues() != 1)
		{
			break;
		}
		
		bool bModifySecondResult = sfTestFlags.EnumModifyEnumeratedFlagValue(1, OU_UINT16_BITS - 1, OU_UINT16_BITS, true);
		
		if (!bModifySecondResult || sfTestFlags.QueryFlagsAllValues() != (uint16ou)(OU_INT16_MIN + 1))
		{
			break;
		}
		
		bool bModifyThirdResult = sfTestFlags.EnumModifyEnumeratedFlagValue(1, 0, OU_UINT16_BITS, true);
		
		if (bModifyThirdResult || sfTestFlags.QueryFlagsAllValues() != (uint16ou)(OU_INT16_MIN + 1))
		{
			break;
		}
		
		bool bModifyFourthResult = sfTestFlags.EnumModifyEnumeratedFlagValue(1, OU_UINT16_BITS - 1, OU_UINT16_BITS, true);
		
		if (bModifyFourthResult || sfTestFlags.QueryFlagsAllValues() != (uint16ou)(OU_INT16_MIN + 1))
		{
			break;
		}
		
		bool bModifyFifthResult = sfTestFlags.EnumModifyEnumeratedFlagValue(1, 0, OU_UINT16_BITS, false);
		
		if (!bModifyFifthResult || sfTestFlags.QueryFlagsAllValues() != (uint16ou)OU_INT16_MIN)
		{
			break;
		}
		
		bool bModifySixthResult = sfTestFlags.EnumModifyEnumeratedFlagValue(1, OU_UINT16_BITS - 1, OU_UINT16_BITS, false);
		
		if (!bModifySixthResult || sfTestFlags.QueryFlagsAllValues() != 0)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags16_EnumSignalFirstEnumeratedFlagValue()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags16 sfTestFlags;

		bool bFirstResult = sfTestFlags.EnumSignalFirstEnumeratedFlagValue(1, 0, OU_UINT16_BITS);

		if (!bFirstResult || sfTestFlags.QueryFlagsAllValues() != 1)
		{
			break;
		}
		
		bool bSecondResult = sfTestFlags.EnumSignalFirstEnumeratedFlagValue(1, 0, OU_UINT16_BITS);
		
		if (bSecondResult || sfTestFlags.QueryFlagsAllValues() != 1)
		{
			break;
		}
		
		bool bThirdResult = sfTestFlags.EnumSignalFirstEnumeratedFlagValue(2, 0, OU_UINT16_BITS - 1);
		
		if (!bThirdResult || sfTestFlags.QueryFlagsAllValues() != 3)
		{
			break;
		}
		
		bool bFourthResult = sfTestFlags.EnumSignalFirstEnumeratedFlagValue(1, OU_UINT16_BITS - 1, OU_UINT16_BITS);
		
		if (bFourthResult || sfTestFlags.QueryFlagsAllValues() != (uint16ou)(OU_INT16_MIN + 3))
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags16_EnumSignalLastEnumeratedFlagValue()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags16 sfTestFlags;
		
		bool bFirstResult = sfTestFlags.EnumSignalLastEnumeratedFlagValue(1, 0, 1);
		
		if (!bFirstResult || sfTestFlags.QueryFlagsAllValues() != 1)
		{
			break;
		}
		
		bool bSecondResult = sfTestFlags.EnumSignalLastEnumeratedFlagValue(1, 0, 1);
		
		if (bSecondResult || sfTestFlags.QueryFlagsAllValues() != 1)
		{
			break;
		}
		
		bool bThirdResult = sfTestFlags.EnumSignalLastEnumeratedFlagValue(1, 1, 2);
		
		if (!bThirdResult || sfTestFlags.QueryFlagsAllValues() != 3)
		{
			break;
		}
		
		bool bFourthResult = sfTestFlags.EnumSignalLastEnumeratedFlagValue(1, OU_UINT16_BITS - 1, OU_UINT16_BITS);
		
		if (bFourthResult || sfTestFlags.QueryFlagsAllValues() != (uint16ou)(OU_INT16_MIN + 3))
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags16_EnumGetEnumeratedFlagValue()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags16 sfTestFlags((uint16ou)(OU_INT16_MIN + 1));
		
		if (!sfTestFlags.EnumGetEnumeratedFlagValue(1, 0, OU_UINT16_BITS))
		{
			break;
		}
	
		if (sfTestFlags.EnumGetEnumeratedFlagValue(2, 0, OU_UINT16_BITS - 1))
		{
			break;
		}
		
		if (sfTestFlags.EnumGetEnumeratedFlagValue(1, 1, OU_UINT16_BITS - 1))
		{
			break;
		}
		
		if (!sfTestFlags.EnumGetEnumeratedFlagValue(1, OU_UINT16_BITS - 1, OU_UINT16_BITS))
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags16_EnumFindFirstEnumeratedFlag()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags16 sfTestFlags((uint16ou)(OU_INT16_MIN + 1));

		unsigned int uiFirstResult = sfTestFlags.EnumFindFirstEnumeratedFlag(1, OU_UINT16_BITS);
		if (uiFirstResult != 0)
		{
			break;
		}

		unsigned int uiSecondResult = sfTestFlags.EnumFindFirstEnumeratedFlag(2, OU_UINT16_BITS - 1);
		if (uiSecondResult != OU_UINT16_BITS - 2)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags16_EnumAllSignalEnumeratedFlags()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags16 sfTestFlags;
		
		sfTestFlags.EnumAllSignalEnumeratedFlags(1, 1);

		if (sfTestFlags.QueryFlagsAllValues() != 1)
		{
			break;
		}

		sfTestFlags.EnumAllSignalEnumeratedFlags(4, OU_UINT16_BITS - 2);

		if (sfTestFlags.QueryFlagsAllValues() != (uint16ou)(OU_UINT16_MAX ^ 2))
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags16_EnumAllDropEnumeratedFlags()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags16 sfTestFlags(OU_UINT16_MAX);
		
		sfTestFlags.EnumAllDropEnumeratedFlags(1, 1);
		
		if (sfTestFlags.QueryFlagsAllValues() != (uint16ou)(OU_UINT16_MAX ^ 1))
		{
			break;
		}
		
		sfTestFlags.EnumAllDropEnumeratedFlags(4, OU_UINT16_BITS - 2);
		
		if (sfTestFlags.QueryFlagsAllValues() != 2)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags16_EnumAllQueryEnumeratedFlags()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags16 sfTestFlags((uint16ou)(OU_INT16_MIN + 1));
		
		uint16ou uiFirstResult = sfTestFlags.EnumAllQueryEnumeratedFlags(1, OU_UINT16_BITS);
		if (uiFirstResult != (uint16ou)(OU_INT16_MIN + 1))
		{
			break;
		}
		
		uint16ou uiSecondResult = sfTestFlags.EnumAllQueryEnumeratedFlags(2, OU_UINT16_BITS - 1);
		if (uiSecondResult != (uint16ou)(OU_INT16_MIN))
		{
			break;
		}
		
		uint16ou uiThirdResult = sfTestFlags.EnumAllQueryEnumeratedFlags(2, OU_UINT16_BITS - 2);
		if (uiThirdResult != 0)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags16_EnumAnyGetEnumeratedFlagValue()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags16 sfTestFlags((uint16ou)(OU_INT16_MIN + 1));
		
		bool bFirstResult = sfTestFlags.EnumAnyGetEnumeratedFlagValue(1, OU_UINT16_BITS);
		if (!bFirstResult)
		{
			break;
		}
		
		bool bSecondResult = sfTestFlags.EnumAnyGetEnumeratedFlagValue(2, OU_UINT16_BITS - 1);
		if (!bSecondResult)
		{
			break;
		}
		
		bool bThirdResult = sfTestFlags.EnumAnyGetEnumeratedFlagValue(2, OU_UINT16_BITS - 2);
		if (bThirdResult)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags16_StoreFlagsEnumeratedValue()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags16 sfTestFlags;

		sfTestFlags.StoreFlagsEnumeratedValue(0x03, 1, 2);

		if (sfTestFlags.QueryFlagsAllValues() != (uint16ou)(2 << 1))
		{
			break;
		}
	
		sfTestFlags.StoreFlagsEnumeratedValue(0x03, OU_UINT16_BITS - 2, 3);
		
		if (sfTestFlags.QueryFlagsAllValues() != ((uint16ou)(2 << 1) | (uint16ou)(OU_INT16_MIN | (OU_INT16_MIN >> 1))))
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags16_RetrieveFlagsEnumeratedValue()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags16 sfTestFlags((uint16ou)(OU_INT16_MIN + 1));
		
		unsigned int uiFirstResult = sfTestFlags.RetrieveFlagsEnumeratedValue(0x3, 1);
		if (uiFirstResult != 0)
		{
			break;
		}
		
		unsigned int uiSecondResult = sfTestFlags.RetrieveFlagsEnumeratedValue(0x3, OU_UINT16_BITS - 2);
		if (uiSecondResult != 2)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}


enum EOUSIMPLEFLAGSFEATURE16
{
	OSF16__MIN,
		
	OSF16_CONSTRUCTORS = OSF16__MIN,
	OSF16_ASSIGNFLAGSALLVALUES,
	OSF16_QUERYFLAGSALLVALUES,
	OSF16_SETFLAGSMASKVALUE,
	OSF16_SIGNALFLAGSMASKVALUE,
	OSF16_DROPFLAGSMASKVALUE,
	OSF16_TOGGLESINGLEFLAGVALUE,
	OSF16_MODIFYSINGLEFLAGVALUE,
	OSF16_ASSIGNFLAGSBYMASK,
	OSF16_ALTERFLAGSBYMASK,
	OSF16_GETFLAGSMASKVALUE,
	OSF16_QUERYFLAGSBYMASK,
	OSF16_ONLYSIGNALSINGLEFLAGOUTOFMASK,
	OSF16_ENUMSETENUMERATEDFLAGVALUE,
	OSF16_ENUMSIGNALENUMERATEDFLAGVALUE,
	OSF16_ENUMDROPENUMERATEDFLAGVALUE,
	OSF16_ENUMTOGGLEENUMERATEDFLAGVALUE,
	OSF16_ENUMMODIFYENUMERATEDFLAGVALUE,
	OSF16_ENUMSIGNALFIRSTENUMERATEDFLAGVALUE,
	OSF16_ENUMSIGNALLASTENUMERATEDFLAGVALUE,
	OSF16_ENUMGETENUMERATEDFLAGVALUE,
	OSF16_ENUMFINDFIRSTENUMERATEDFLAG,
	OSF16_ENUMALLSIGNALENUMERATEDFLAGS,
	OSF16_ENUMALLDROPENUMERATEDFLAGS,
	OSF16_ENUMALLQUERYENUMERATEDFLAGS,
	OSF16_ENUMANYGETENUMERATEDFLAGVALUE,
	OSF16_STOREFLAGSENUMERATEDVALUE,
	OSF16_RETRIEVEFLAGSENUMERATEDVALUE,

	OSF16__MAX,
};

template<>
CFeatureTestProcedure const CEnumUnsortedElementArray<EOUSIMPLEFLAGSFEATURE16, OSF16__MAX, CFeatureTestProcedure>::m_aetElementArray[] =
{
	&TestSimpleFlags16_Constructors, // OSF16_CONSTRUCTORS
	&TestSimpleFlags16_AssignFlagsAllValues, // OSF16_ASSIGNFLAGSALLVALUES,
	&TestSimpleFlags16_QueryFlagsAllValues, // OSF16_QUERYFLAGSALLVALUES,
	&TestSimpleFlags16_SetFlagsMaskValue, // OSF16_SETFLAGSMASKVALUE,
	&TestSimpleFlags16_SignalFlagsMaskValue, // OSF16_SIGNALFLAGSMASKVALUE,
	&TestSimpleFlags16_DropFlagsMaskValue, // OSF16_DROPFLAGSMASKVALUE,
	&TestSimpleFlags16_ToggleSingleFlagValue, // OSF16_TOGGLESINGLEFLAGVALUE,
	&TestSimpleFlags16_ModifySingleFlagValue, // OSF16_MODIFYSINGLEFLAGVALUE,
	&TestSimpleFlags16_AssignFlagsByMask, // OSF16_ASSIGNFLAGSBYMASK,
	&TestSimpleFlags16_AlterFlagsByMask, // OSF16_ALTERFLAGSBYMASK,
	&TestSimpleFlags16_GetFlagsMaskValue, // OSF16_GETFLAGSMASKVALUE,
	&TestSimpleFlags16_QueryFlagsByMask, // OSF16_QUERYFLAGSBYMASK,
	&TestSimpleFlags16_OnlySignalSingleFlagOutOfMask, // OSF16_ONLYSIGNALSINGLEFLAGOUTOFMASK,
	&TestSimpleFlags16_EnumSetEnumeratedFlagValue, // OSF16_ENUMSETENUMERATEDFLAGVALUE,
	&TestSimpleFlags16_EnumSignalEnumeratedFlagValue, // OSF16_ENUMSIGNALENUMERATEDFLAGVALUE,
	&TestSimpleFlags16_EnumDropEnumeratedFlagValue, // OSF16_ENUMDROPENUMERATEDFLAGVALUE,
	&TestSimpleFlags16_EnumToggleEnumeratedFlagValue, // OSF16_ENUMTOGGLEENUMERATEDFLAGVALUE,
	&TestSimpleFlags16_EnumModifyEnumeratedFlagValue, // OSF16_ENUMMODIFYENUMERATEDFLAGVALUE,
	&TestSimpleFlags16_EnumSignalFirstEnumeratedFlagValue, // OSF16_ENUMSIGNALFIRSTENUMERATEDFLAGVALUE,
	&TestSimpleFlags16_EnumSignalLastEnumeratedFlagValue, // OSF16_ENUMSIGNALLASTENUMERATEDFLAGVALUE,
	&TestSimpleFlags16_EnumGetEnumeratedFlagValue, // OSF16_ENUMGETENUMERATEDFLAGVALUE,
	&TestSimpleFlags16_EnumFindFirstEnumeratedFlag, // OSF16_ENUMFINDFIRSTENUMERATEDFLAG,
	&TestSimpleFlags16_EnumAllSignalEnumeratedFlags, // OSF16_ENUMALLSIGNALENUMERATEDFLAGS,
	&TestSimpleFlags16_EnumAllDropEnumeratedFlags, // OSF16_ENUMALLDROPENUMERATEDFLAGS,
	&TestSimpleFlags16_EnumAllQueryEnumeratedFlags, // OSF16_ENUMALLQUERYENUMERATEDFLAGS,
	&TestSimpleFlags16_EnumAnyGetEnumeratedFlagValue, // OSF16_ENUMANYGETENUMERATEDFLAGVALUE,
	&TestSimpleFlags16_StoreFlagsEnumeratedValue, // OSF16_STOREFLAGSENUMERATEDVALUE,
	&TestSimpleFlags16_RetrieveFlagsEnumeratedValue, // OSF16_RETRIEVEFLAGSENUMERATEDVALUE,
};
static const CEnumUnsortedElementArray<EOUSIMPLEFLAGSFEATURE16, OSF16__MAX, CFeatureTestProcedure> g_afnSimpleFlags16FeatureTestProcedures;

template<>
const char *const CEnumUnsortedElementArray<EOUSIMPLEFLAGSFEATURE16, OSF16__MAX, const char *>::m_aetElementArray[] =
{
	"Constructors", // OSF16_CONSTRUCTORS
	"AssignFlagsAllValues", // OSF16_ASSIGNFLAGSALLVALUES,
	"QueryFlagsAllValues", // OSF16_QUERYFLAGSALLVALUES,
	"SetFlagsMaskValue", // OSF16_SETFLAGSMASKVALUE,
	"SignalFlagsMaskValue", // OSF16_SIGNALFLAGSMASKVALUE,
	"DropFlagsMaskValue", // OSF16_DROPFLAGSMASKVALUE,
	"ToggleSingleFlagValue", // OSF16_TOGGLESINGLEFLAGVALUE,
	"ModifySingleFlagValue", // OSF16_MODIFYSINGLEFLAGVALUE,
	"AssignFlagsByMask", // OSF16_ASSIGNFLAGSBYMASK,
	"AlterFlagsByMask", // OSF16_ALTERFLAGSBYMASK,
	"GetFlagsMaskValue", // OSF16_GETFLAGSMASKVALUE,
	"QueryFlagsByMask", // OSF16_QUERYFLAGSBYMASK,
	"OnlySignalSingleFlagOutOfMask", // OSF16_ONLYSIGNALSINGLEFLAGOUTOFMASK,
	"EnumSetEnumeratedFlagValue", // OSF16_ENUMSETENUMERATEDFLAGVALUE,
	"EnumSignalEnumeratedFlagValue", // OSF16_ENUMSIGNALENUMERATEDFLAGVALUE,
	"EnumDropEnumeratedFlagValue", // OSF16_ENUMDROPENUMERATEDFLAGVALUE,
	"EnumToggleEnumeratedFlagValue", // OSF16_ENUMTOGGLEENUMERATEDFLAGVALUE,
	"EnumModifyEnumeratedFlagValue", // OSF16_ENUMMODIFYENUMERATEDFLAGVALUE,
	"EnumSignalFirstEnumeratedFlagValue", // OSF16_ENUMSIGNALFIRSTENUMERATEDFLAGVALUE,
	"EnumSignalLastEnumeratedFlagValue", // OSF16_ENUMSIGNALLASTENUMERATEDFLAGVALUE,
	"EnumGetEnumeratedFlagValue", // OSF16_ENUMGETENUMERATEDFLAGVALUE,
	"EnumFindFirstEnumeratedFlag", // OSF16_ENUMFINDFIRSTENUMERATEDFLAG,
	"EnumAllSignalEnumeratedFlags", // OSF16_ENUMALLSIGNALENUMERATEDFLAGS,
	"EnumAllDropEnumeratedFlags", // OSF16_ENUMALLDROPENUMERATEDFLAGS,
	"EnumAllQueryEnumeratedFlags", // OSF16_ENUMALLQUERYENUMERATEDFLAGS,
	"EnumAnyGetEnumeratedFlagValue", // OSF16_ENUMANYGETENUMERATEDFLAGVALUE,
	"StoreFlagsEnumeratedValue", // OSF16_STOREFLAGSENUMERATEDVALUE,
	"RetrieveFlagsEnumeratedValue", // OSF16_RETRIEVEFLAGSENUMERATEDVALUE,
};
static const CEnumUnsortedElementArray<EOUSIMPLEFLAGSFEATURE16, OSF16__MAX, const char *> g_aszSimpleFlags16FeatureTestNames;


bool TestSimpleFlags16(unsigned int &nOutSuccessCount, unsigned int &nOutTestCount)
{
	return TestSubsystem(nOutSuccessCount, nOutTestCount, OSF16__MAX, g_aszSimpleFlags16FeatureTestNames.GetStoragePointer(), g_afnSimpleFlags16FeatureTestProcedures.GetStoragePointer());
}


//////////////////////////////////////////////////////////////////////////

typedef CSimpleFlagsTemplate<uint8ou> CSimpleFlags8;

const uint8ou g_uiTestValue8 = (uint8ou)0xA5;
const uint8ou g_uiTestMask8 = (uint8ou)0xC6;
const uint8ou g_uiTestBit8 = (uint8ou)OU_INT8_MIN;
const uint8ou g_uiTestAnotherBit8 = (uint8ou)((uint8ou)OU_INT8_MIN >> 1);


bool TestSimpleFlags8_Constructors()
{
	bool bResult = false;
	
	do
	{
		if (sizeof(CSimpleFlags8::value_type) != sizeof(uint8ou) || sizeof(CSimpleFlags8) != sizeof(uint8ou))
		{
			break;
		}

		CSimpleFlags8 sfEmptyFlags;

		if (sfEmptyFlags.QueryFlagsAllValues())
		{
			break;
		}

		CSimpleFlags8 sfFullFlags(OU_UINT8_MAX);
		
		if (sfFullFlags.QueryFlagsAllValues() != OU_UINT8_MAX)
		{
			break;
		}

		CSimpleFlags8 sfCopyOfFullFlags(sfFullFlags);

		if (sfCopyOfFullFlags.QueryFlagsAllValues() != OU_UINT8_MAX)
		{
			break;
		}
	
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags8_AssignFlagsAllValues()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags8 sfTestFlags;

		sfTestFlags.AssignFlagsAllValues(OU_UINT8_MAX);

		if (sfTestFlags.QueryFlagsAllValues() != OU_UINT8_MAX)
		{
			break;
		}

		sfTestFlags.AssignFlagsAllValues(0);

		if (sfTestFlags.QueryFlagsAllValues() != 0)
		{
			break;
		}
	
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags8_QueryFlagsAllValues()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags8 sfTestFlags(g_uiTestValue8);
		
		if (sfTestFlags.QueryFlagsAllValues() != g_uiTestValue8)
		{
			break;
		}

		// Double check to be sure ;-)
		if (sfTestFlags.QueryFlagsAllValues() != g_uiTestValue8)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags8_SetFlagsMaskValue()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags8 sfTestFlags(g_uiTestValue8);

		sfTestFlags.SetFlagsMaskValue(g_uiTestMask8, true);

		if (sfTestFlags.QueryFlagsAllValues() != (uint8ou)(g_uiTestValue8 | g_uiTestMask8))
		{
			break;
		}

		sfTestFlags.SetFlagsMaskValue(g_uiTestValue8, false);

		if (sfTestFlags.QueryFlagsAllValues() != (uint8ou)(~g_uiTestValue8 & g_uiTestMask8))
		{
			break;
		}
		

		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags8_SignalFlagsMaskValue()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags8 sfTestFlags(g_uiTestValue8);
		
		sfTestFlags.SignalFlagsMaskValue(g_uiTestMask8);
		
		if (sfTestFlags.QueryFlagsAllValues() != (uint8ou)(g_uiTestValue8 | g_uiTestMask8))
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags8_DropFlagsMaskValue()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags8 sfTestFlags(g_uiTestValue8);
		
		sfTestFlags.DropFlagsMaskValue(g_uiTestMask8);
		
		if (sfTestFlags.QueryFlagsAllValues() != (uint8ou)(g_uiTestValue8 & ~g_uiTestMask8))
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags8_ToggleSingleFlagValue()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags8 sfTestFlags(g_uiTestValue8);
		
		bool bPreviousValue = sfTestFlags.ToggleSingleFlagValue(g_uiTestBit8);
		
		if (bPreviousValue != ((g_uiTestValue8 & g_uiTestBit8) != 0) || sfTestFlags.QueryFlagsAllValues() != (uint8ou)(g_uiTestValue8 ^ g_uiTestBit8))
		{
			break;
		}

		bool bAnotherPreviousValue = sfTestFlags.ToggleSingleFlagValue(g_uiTestBit8);
		
		if (bAnotherPreviousValue == bPreviousValue || sfTestFlags.QueryFlagsAllValues() != g_uiTestValue8)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags8_ModifySingleFlagValue()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags8 sfTestFlags(g_uiTestValue8);
		
		bool bFirstModification = sfTestFlags.ModifySingleFlagValue(g_uiTestBit8, true);
		
		if (bFirstModification != ((g_uiTestValue8 & g_uiTestBit8) != g_uiTestBit8) || sfTestFlags.QueryFlagsAllValues() != (uint8ou)(g_uiTestValue8 | g_uiTestBit8))
		{
			break;
		}
		
		bool bAnotherModification = sfTestFlags.ModifySingleFlagValue(g_uiTestBit8, bFirstModification);
		
		if (bAnotherModification == bFirstModification || sfTestFlags.QueryFlagsAllValues() != (bFirstModification ? (uint8ou)(g_uiTestValue8 | g_uiTestBit8) : (uint8ou)(g_uiTestValue8 & ~g_uiTestBit8)))
		{
			break;
		}

		bool bYetAnotherModification = sfTestFlags.ModifySingleFlagValue(g_uiTestBit8, bAnotherModification);

		if (bYetAnotherModification != bAnotherModification || sfTestFlags.QueryFlagsAllValues() != (bAnotherModification ? (uint8ou)(g_uiTestValue8 | g_uiTestBit8) : (uint8ou)(g_uiTestValue8 & ~g_uiTestBit8)))
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags8_AssignFlagsByMask()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags8 sfTestFlags(g_uiTestValue8);

		uint8ou uiPreviousFlags = sfTestFlags.AssignFlagsByMask(g_uiTestMask8, g_uiTestMask8);

		const uint8ou uiNewFlags = (g_uiTestValue8 & ~g_uiTestMask8) | g_uiTestMask8;

		if (uiPreviousFlags != g_uiTestValue8 || sfTestFlags.QueryFlagsAllValues() != uiNewFlags)
		{
			break;
		}

		uint8ou uiAnotherPreviousFlags = sfTestFlags.AssignFlagsByMask(g_uiTestValue8, 0);

		const uint8ou uiAnotherNewFlags = uiNewFlags & ~g_uiTestValue8;

		if (uiAnotherPreviousFlags != uiNewFlags || sfTestFlags.QueryFlagsAllValues() != uiAnotherNewFlags)
		{
			break;
		}
	
		uint8ou uiYetAnotherPreviousFlags = sfTestFlags.AssignFlagsByMask(g_uiTestMask8, g_uiTestMask8 & g_uiTestValue8);
		OU_ASSERT((g_uiTestMask8 & g_uiTestValue8) != 0); // Test degeneration
		
		const uint8ou uiYetAnotherNewFlags = (uiAnotherNewFlags & ~g_uiTestMask8) | (g_uiTestMask8 & g_uiTestValue8);
		OU_ASSERT(uiYetAnotherNewFlags != OU_UINT8_MAX); // Test degeneration
		
		if (uiYetAnotherPreviousFlags != uiAnotherNewFlags || sfTestFlags.QueryFlagsAllValues() != uiYetAnotherNewFlags)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags8_AlterFlagsByMask()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags8 sfTestFlags(g_uiTestValue8);
		
		bool bWasModification = sfTestFlags.AlterFlagsByMask(g_uiTestMask8, g_uiTestMask8);
		
		const uint8ou uiNewFlags = (g_uiTestValue8 & ~g_uiTestMask8) | g_uiTestMask8;
		
		if (bWasModification != ((g_uiTestValue8 & g_uiTestMask8) != g_uiTestMask8) || sfTestFlags.QueryFlagsAllValues() != uiNewFlags)
		{
			break;
		}
		
		bool bWasAnotherModification = sfTestFlags.AlterFlagsByMask(g_uiTestValue8, 0);
		
		const uint8ou uiAnotherNewFlags = uiNewFlags & ~g_uiTestValue8;
		
		if (bWasAnotherModification != ((uiNewFlags & g_uiTestValue8) != 0) || sfTestFlags.QueryFlagsAllValues() != uiAnotherNewFlags)
		{
			break;
		}
		
		bool bWasAnotherModificationRepeated = sfTestFlags.AlterFlagsByMask(g_uiTestValue8, 0);
		
		if (bWasAnotherModificationRepeated || sfTestFlags.QueryFlagsAllValues() != uiAnotherNewFlags)
		{
			break;
		}
		
		bool bWasYetAnotherModification = sfTestFlags.AlterFlagsByMask(g_uiTestMask8, g_uiTestMask8 & g_uiTestValue8);
		OU_ASSERT((g_uiTestMask8 & g_uiTestValue8) != 0); // Test degeneration
		
		const uint8ou uiYetAnotherNewFlags = (uiAnotherNewFlags & ~g_uiTestMask8) | (g_uiTestMask8 & g_uiTestValue8);
		OU_ASSERT(uiYetAnotherNewFlags != OU_UINT8_MAX); // Test degeneration
		
		if (bWasYetAnotherModification != ((uiAnotherNewFlags & g_uiTestMask8) != (g_uiTestMask8 & g_uiTestValue8)) || sfTestFlags.QueryFlagsAllValues() != uiYetAnotherNewFlags)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags8_GetFlagsMaskValue()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags8 sfTestFlags(g_uiTestValue8);
		
		if (sfTestFlags.GetFlagsMaskValue(g_uiTestMask8) != ((g_uiTestValue8 & g_uiTestMask8) != 0))
		{
			break;
		}
		
		if (sfTestFlags.GetFlagsMaskValue((uint8ou)(~g_uiTestValue8)))
		{
			break;
		}
		
		if (!sfTestFlags.GetFlagsMaskValue(OU_UINT8_MAX))
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags8_QueryFlagsByMask()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags8 sfTestFlags(g_uiTestValue8);
		
		if (sfTestFlags.QueryFlagsByMask(g_uiTestMask8) != (uint8ou)(g_uiTestValue8 & g_uiTestMask8))
		{
			break;
		}
		
		if (sfTestFlags.QueryFlagsByMask(0))
		{
			break;
		}
		
		if (sfTestFlags.QueryFlagsByMask(OU_UINT8_MAX) != g_uiTestValue8)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags8_OnlySignalSingleFlagOutOfMask()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags8 sfTestFlags(g_uiTestValue8);
		OU_ASSERT(g_uiTestValue8 != 0); // Test degeneration
		
		if (sfTestFlags.OnlySignalSingleFlagOutOfMask(OU_UINT8_MAX, g_uiTestBit8))
		{
			break;
		}

		if (sfTestFlags.QueryFlagsAllValues() != g_uiTestValue8)
		{
			break;
		}
		
		sfTestFlags.AssignFlagsAllValues(0);

		if (!sfTestFlags.OnlySignalSingleFlagOutOfMask(g_uiTestBit8, g_uiTestBit8))
		{
			break;
		}
		
		if (sfTestFlags.QueryFlagsAllValues() != g_uiTestBit8)
		{
			break;
		}
		
		if (sfTestFlags.OnlySignalSingleFlagOutOfMask(g_uiTestBit8, g_uiTestBit8))
		{
			break;
		}
		
		if (sfTestFlags.QueryFlagsAllValues() != g_uiTestBit8)
		{
			break;
		}
		
		if (sfTestFlags.OnlySignalSingleFlagOutOfMask(OU_UINT8_MAX, g_uiTestAnotherBit8))
		{
			break;
		}
		
		if (sfTestFlags.QueryFlagsAllValues() != g_uiTestBit8)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags8_EnumSetEnumeratedFlagValue()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags8 sfTestFlags;
		
		sfTestFlags.EnumSetEnumeratedFlagValue(1, 0, OU_UINT8_BITS, true);

		if (sfTestFlags.QueryFlagsAllValues() != 1)
		{
			break;
		}
	
		sfTestFlags.EnumSetEnumeratedFlagValue(1, OU_UINT8_BITS - 1, OU_UINT8_BITS, true);
		
		if (sfTestFlags.QueryFlagsAllValues() != (uint8ou)(OU_INT8_MIN + 1))
		{
			break;
		}
		
		sfTestFlags.EnumSetEnumeratedFlagValue(1, 0, OU_UINT8_BITS, false);
		
		if (sfTestFlags.QueryFlagsAllValues() != (uint8ou)OU_INT8_MIN)
		{
			break;
		}
		
		sfTestFlags.EnumSetEnumeratedFlagValue(1, OU_UINT8_BITS - 1, OU_UINT8_BITS, false);
		
		if (sfTestFlags.QueryFlagsAllValues() != 0)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags8_EnumSignalEnumeratedFlagValue()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags8 sfTestFlags;
		
		sfTestFlags.EnumSignalEnumeratedFlagValue(1, 0, OU_UINT8_BITS);
		
		if (sfTestFlags.QueryFlagsAllValues() != 1)
		{
			break;
		}
		
		sfTestFlags.EnumSignalEnumeratedFlagValue(1, OU_UINT8_BITS - 1, OU_UINT8_BITS);
		
		if (sfTestFlags.QueryFlagsAllValues() != (uint8ou)(OU_INT8_MIN + 1))
		{
			break;
		}
		
		sfTestFlags.EnumSignalEnumeratedFlagValue(1, 0, OU_UINT8_BITS);
		
		if (sfTestFlags.QueryFlagsAllValues() != (uint8ou)(OU_INT8_MIN + 1))
		{
			break;
		}
		
		sfTestFlags.EnumSignalEnumeratedFlagValue(1, OU_UINT8_BITS - 1, OU_UINT8_BITS);
		
		if (sfTestFlags.QueryFlagsAllValues() != (uint8ou)(OU_INT8_MIN + 1))
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags8_EnumDropEnumeratedFlagValue()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags8 sfTestFlags(OU_UINT8_MAX);
		
		sfTestFlags.EnumDropEnumeratedFlagValue(1, 0, OU_UINT8_BITS);
		
		if (sfTestFlags.QueryFlagsAllValues() != (OU_UINT8_MAX ^ 1))
		{
			break;
		}
		
		sfTestFlags.EnumDropEnumeratedFlagValue(1, OU_UINT8_BITS - 1, OU_UINT8_BITS);
		
		if (sfTestFlags.QueryFlagsAllValues() != (uint8ou)~(OU_INT8_MIN + 1))
		{
			break;
		}
		
		sfTestFlags.EnumDropEnumeratedFlagValue(1, 0, OU_UINT8_BITS);
		
		if (sfTestFlags.QueryFlagsAllValues() != (uint8ou)~(OU_INT8_MIN + 1))
		{
			break;
		}
		
		sfTestFlags.EnumDropEnumeratedFlagValue(1, OU_UINT8_BITS - 1, OU_UINT8_BITS);
		
		if (sfTestFlags.QueryFlagsAllValues() != (uint8ou)~(OU_INT8_MIN + 1))
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags8_EnumToggleEnumeratedFlagValue()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags8 sfTestFlags;
		
		bool bToggleFirstResult = sfTestFlags.EnumToggleEnumeratedFlagValue(1, 0, OU_UINT8_BITS);
		
		if (bToggleFirstResult || sfTestFlags.QueryFlagsAllValues() != 1)
		{
			break;
		}
		
		bool bToggleSecondResult = sfTestFlags.EnumToggleEnumeratedFlagValue(1, OU_UINT8_BITS - 1, OU_UINT8_BITS);
		
		if (bToggleSecondResult || sfTestFlags.QueryFlagsAllValues() != (uint8ou)(OU_INT8_MIN + 1))
		{
			break;
		}
		
		bool bToggleThirdResult = sfTestFlags.EnumToggleEnumeratedFlagValue(1, 0, OU_UINT8_BITS);
		
		if (!bToggleThirdResult || sfTestFlags.QueryFlagsAllValues() != (uint8ou)OU_INT8_MIN)
		{
			break;
		}
		
		bool bToggleFourthResult = sfTestFlags.EnumToggleEnumeratedFlagValue(1, OU_UINT8_BITS - 1, OU_UINT8_BITS);
		
		if (!bToggleFourthResult || sfTestFlags.QueryFlagsAllValues() != 0)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags8_EnumModifyEnumeratedFlagValue()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags8 sfTestFlags;
		
		bool bModifyFirstResult = sfTestFlags.EnumModifyEnumeratedFlagValue(1, 0, OU_UINT8_BITS, true);
		
		if (!bModifyFirstResult || sfTestFlags.QueryFlagsAllValues() != 1)
		{
			break;
		}
		
		bool bModifySecondResult = sfTestFlags.EnumModifyEnumeratedFlagValue(1, OU_UINT8_BITS - 1, OU_UINT8_BITS, true);
		
		if (!bModifySecondResult || sfTestFlags.QueryFlagsAllValues() != (uint8ou)(OU_INT8_MIN + 1))
		{
			break;
		}
		
		bool bModifyThirdResult = sfTestFlags.EnumModifyEnumeratedFlagValue(1, 0, OU_UINT8_BITS, true);
		
		if (bModifyThirdResult || sfTestFlags.QueryFlagsAllValues() != (uint8ou)(OU_INT8_MIN + 1))
		{
			break;
		}
		
		bool bModifyFourthResult = sfTestFlags.EnumModifyEnumeratedFlagValue(1, OU_UINT8_BITS - 1, OU_UINT8_BITS, true);
		
		if (bModifyFourthResult || sfTestFlags.QueryFlagsAllValues() != (uint8ou)(OU_INT8_MIN + 1))
		{
			break;
		}
		
		bool bModifyFifthResult = sfTestFlags.EnumModifyEnumeratedFlagValue(1, 0, OU_UINT8_BITS, false);
		
		if (!bModifyFifthResult || sfTestFlags.QueryFlagsAllValues() != (uint8ou)OU_INT8_MIN)
		{
			break;
		}
		
		bool bModifySixthResult = sfTestFlags.EnumModifyEnumeratedFlagValue(1, OU_UINT8_BITS - 1, OU_UINT8_BITS, false);
		
		if (!bModifySixthResult || sfTestFlags.QueryFlagsAllValues() != 0)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags8_EnumSignalFirstEnumeratedFlagValue()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags8 sfTestFlags;

		bool bFirstResult = sfTestFlags.EnumSignalFirstEnumeratedFlagValue(1, 0, OU_UINT8_BITS);

		if (!bFirstResult || sfTestFlags.QueryFlagsAllValues() != 1)
		{
			break;
		}
		
		bool bSecondResult = sfTestFlags.EnumSignalFirstEnumeratedFlagValue(1, 0, OU_UINT8_BITS);
		
		if (bSecondResult || sfTestFlags.QueryFlagsAllValues() != 1)
		{
			break;
		}
		
		bool bThirdResult = sfTestFlags.EnumSignalFirstEnumeratedFlagValue(2, 0, OU_UINT8_BITS - 1);
		
		if (!bThirdResult || sfTestFlags.QueryFlagsAllValues() != 3)
		{
			break;
		}
		
		bool bFourthResult = sfTestFlags.EnumSignalFirstEnumeratedFlagValue(1, OU_UINT8_BITS - 1, OU_UINT8_BITS);
		
		if (bFourthResult || sfTestFlags.QueryFlagsAllValues() != (uint8ou)(OU_INT8_MIN + 3))
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags8_EnumSignalLastEnumeratedFlagValue()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags8 sfTestFlags;
		
		bool bFirstResult = sfTestFlags.EnumSignalLastEnumeratedFlagValue(1, 0, 1);
		
		if (!bFirstResult || sfTestFlags.QueryFlagsAllValues() != 1)
		{
			break;
		}
		
		bool bSecondResult = sfTestFlags.EnumSignalLastEnumeratedFlagValue(1, 0, 1);
		
		if (bSecondResult || sfTestFlags.QueryFlagsAllValues() != 1)
		{
			break;
		}
		
		bool bThirdResult = sfTestFlags.EnumSignalLastEnumeratedFlagValue(1, 1, 2);
		
		if (!bThirdResult || sfTestFlags.QueryFlagsAllValues() != 3)
		{
			break;
		}
		
		bool bFourthResult = sfTestFlags.EnumSignalLastEnumeratedFlagValue(1, OU_UINT8_BITS - 1, OU_UINT8_BITS);
		
		if (bFourthResult || sfTestFlags.QueryFlagsAllValues() != (uint8ou)(OU_INT8_MIN + 3))
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags8_EnumGetEnumeratedFlagValue()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags8 sfTestFlags((uint8ou)(OU_INT8_MIN + 1));
		
		if (!sfTestFlags.EnumGetEnumeratedFlagValue(1, 0, OU_UINT8_BITS))
		{
			break;
		}
	
		if (sfTestFlags.EnumGetEnumeratedFlagValue(2, 0, OU_UINT8_BITS - 1))
		{
			break;
		}
		
		if (sfTestFlags.EnumGetEnumeratedFlagValue(1, 1, OU_UINT8_BITS - 1))
		{
			break;
		}
		
		if (!sfTestFlags.EnumGetEnumeratedFlagValue(1, OU_UINT8_BITS - 1, OU_UINT8_BITS))
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags8_EnumFindFirstEnumeratedFlag()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags8 sfTestFlags((uint8ou)(OU_INT8_MIN + 1));

		unsigned int uiFirstResult = sfTestFlags.EnumFindFirstEnumeratedFlag(1, OU_UINT8_BITS);
		if (uiFirstResult != 0)
		{
			break;
		}

		unsigned int uiSecondResult = sfTestFlags.EnumFindFirstEnumeratedFlag(2, OU_UINT8_BITS - 1);
		if (uiSecondResult != OU_UINT8_BITS - 2)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags8_EnumAllSignalEnumeratedFlags()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags8 sfTestFlags;
		
		sfTestFlags.EnumAllSignalEnumeratedFlags(1, 1);

		if (sfTestFlags.QueryFlagsAllValues() != 1)
		{
			break;
		}

		sfTestFlags.EnumAllSignalEnumeratedFlags(4, OU_UINT8_BITS - 2);

		if (sfTestFlags.QueryFlagsAllValues() != (uint8ou)(OU_UINT8_MAX ^ 2))
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags8_EnumAllDropEnumeratedFlags()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags8 sfTestFlags(OU_UINT8_MAX);
		
		sfTestFlags.EnumAllDropEnumeratedFlags(1, 1);
		
		if (sfTestFlags.QueryFlagsAllValues() != (uint8ou)(OU_UINT8_MAX ^ 1))
		{
			break;
		}
		
		sfTestFlags.EnumAllDropEnumeratedFlags(4, OU_UINT8_BITS - 2);
		
		if (sfTestFlags.QueryFlagsAllValues() != 2)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags8_EnumAllQueryEnumeratedFlags()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags8 sfTestFlags((uint8ou)(OU_INT8_MIN + 1));
		
		uint8ou uiFirstResult = sfTestFlags.EnumAllQueryEnumeratedFlags(1, OU_UINT8_BITS);
		if (uiFirstResult != (uint8ou)(OU_INT8_MIN + 1))
		{
			break;
		}
		
		uint8ou uiSecondResult = sfTestFlags.EnumAllQueryEnumeratedFlags(2, OU_UINT8_BITS - 1);
		if (uiSecondResult != (uint8ou)(OU_INT8_MIN))
		{
			break;
		}
		
		uint8ou uiThirdResult = sfTestFlags.EnumAllQueryEnumeratedFlags(2, OU_UINT8_BITS - 2);
		if (uiThirdResult != 0)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags8_EnumAnyGetEnumeratedFlagValue()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags8 sfTestFlags((uint8ou)(OU_INT8_MIN + 1));
		
		bool bFirstResult = sfTestFlags.EnumAnyGetEnumeratedFlagValue(1, OU_UINT8_BITS);
		if (!bFirstResult)
		{
			break;
		}
		
		bool bSecondResult = sfTestFlags.EnumAnyGetEnumeratedFlagValue(2, OU_UINT8_BITS - 1);
		if (!bSecondResult)
		{
			break;
		}
		
		bool bThirdResult = sfTestFlags.EnumAnyGetEnumeratedFlagValue(2, OU_UINT8_BITS - 2);
		if (bThirdResult)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags8_StoreFlagsEnumeratedValue()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags8 sfTestFlags;

		sfTestFlags.StoreFlagsEnumeratedValue(0x03, 1, 2);

		if (sfTestFlags.QueryFlagsAllValues() != (uint8ou)(2 << 1))
		{
			break;
		}
	
		sfTestFlags.StoreFlagsEnumeratedValue(0x03, OU_UINT8_BITS - 2, 3);
		
		if (sfTestFlags.QueryFlagsAllValues() != ((uint8ou)(2 << 1) | (uint8ou)(OU_INT8_MIN | (OU_INT8_MIN >> 1))))
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestSimpleFlags8_RetrieveFlagsEnumeratedValue()
{
	bool bResult = false;
	
	do
	{
		CSimpleFlags8 sfTestFlags((uint8ou)(OU_INT8_MIN + 1));
		
		unsigned int uiFirstResult = sfTestFlags.RetrieveFlagsEnumeratedValue(0x3, 1);
		if (uiFirstResult != 0)
		{
			break;
		}
		
		unsigned int uiSecondResult = sfTestFlags.RetrieveFlagsEnumeratedValue(0x3, OU_UINT8_BITS - 2);
		if (uiSecondResult != 2)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}


enum EOUSIMPLEFLAGSFEATURE8
{
	OSF8__MIN,
		
	OSF8_CONSTRUCTORS = OSF8__MIN,
	OSF8_ASSIGNFLAGSALLVALUES,
	OSF8_QUERYFLAGSALLVALUES,
	OSF8_SETFLAGSMASKVALUE,
	OSF8_SIGNALFLAGSMASKVALUE,
	OSF8_DROPFLAGSMASKVALUE,
	OSF8_TOGGLESINGLEFLAGVALUE,
	OSF8_MODIFYSINGLEFLAGVALUE,
	OSF8_ASSIGNFLAGSBYMASK,
	OSF8_ALTERFLAGSBYMASK,
	OSF8_GETFLAGSMASKVALUE,
	OSF8_QUERYFLAGSBYMASK,
	OSF8_ONLYSIGNALSINGLEFLAGOUTOFMASK,
	OSF8_ENUMSETENUMERATEDFLAGVALUE,
	OSF8_ENUMSIGNALENUMERATEDFLAGVALUE,
	OSF8_ENUMDROPENUMERATEDFLAGVALUE,
	OSF8_ENUMTOGGLEENUMERATEDFLAGVALUE,
	OSF8_ENUMMODIFYENUMERATEDFLAGVALUE,
	OSF8_ENUMSIGNALFIRSTENUMERATEDFLAGVALUE,
	OSF8_ENUMSIGNALLASTENUMERATEDFLAGVALUE,
	OSF8_ENUMGETENUMERATEDFLAGVALUE,
	OSF8_ENUMFINDFIRSTENUMERATEDFLAG,
	OSF8_ENUMALLSIGNALENUMERATEDFLAGS,
	OSF8_ENUMALLDROPENUMERATEDFLAGS,
	OSF8_ENUMALLQUERYENUMERATEDFLAGS,
	OSF8_ENUMANYGETENUMERATEDFLAGVALUE,
	OSF8_STOREFLAGSENUMERATEDVALUE,
	OSF8_RETRIEVEFLAGSENUMERATEDVALUE,

	OSF8__MAX,
};

template<>
CFeatureTestProcedure const CEnumUnsortedElementArray<EOUSIMPLEFLAGSFEATURE8, OSF8__MAX, CFeatureTestProcedure>::m_aetElementArray[] =
{
	&TestSimpleFlags8_Constructors, // OSF8_CONSTRUCTORS
	&TestSimpleFlags8_AssignFlagsAllValues, // OSF8_ASSIGNFLAGSALLVALUES,
	&TestSimpleFlags8_QueryFlagsAllValues, // OSF8_QUERYFLAGSALLVALUES,
	&TestSimpleFlags8_SetFlagsMaskValue, // OSF8_SETFLAGSMASKVALUE,
	&TestSimpleFlags8_SignalFlagsMaskValue, // OSF8_SIGNALFLAGSMASKVALUE,
	&TestSimpleFlags8_DropFlagsMaskValue, // OSF8_DROPFLAGSMASKVALUE,
	&TestSimpleFlags8_ToggleSingleFlagValue, // OSF8_TOGGLESINGLEFLAGVALUE,
	&TestSimpleFlags8_ModifySingleFlagValue, // OSF8_MODIFYSINGLEFLAGVALUE,
	&TestSimpleFlags8_AssignFlagsByMask, // OSF8_ASSIGNFLAGSBYMASK,
	&TestSimpleFlags8_AlterFlagsByMask, // OSF8_ALTERFLAGSBYMASK,
	&TestSimpleFlags8_GetFlagsMaskValue, // OSF8_GETFLAGSMASKVALUE,
	&TestSimpleFlags8_QueryFlagsByMask, // OSF8_QUERYFLAGSBYMASK,
	&TestSimpleFlags8_OnlySignalSingleFlagOutOfMask, // OSF8_ONLYSIGNALSINGLEFLAGOUTOFMASK,
	&TestSimpleFlags8_EnumSetEnumeratedFlagValue, // OSF8_ENUMSETENUMERATEDFLAGVALUE,
	&TestSimpleFlags8_EnumSignalEnumeratedFlagValue, // OSF8_ENUMSIGNALENUMERATEDFLAGVALUE,
	&TestSimpleFlags8_EnumDropEnumeratedFlagValue, // OSF8_ENUMDROPENUMERATEDFLAGVALUE,
	&TestSimpleFlags8_EnumToggleEnumeratedFlagValue, // OSF8_ENUMTOGGLEENUMERATEDFLAGVALUE,
	&TestSimpleFlags8_EnumModifyEnumeratedFlagValue, // OSF8_ENUMMODIFYENUMERATEDFLAGVALUE,
	&TestSimpleFlags8_EnumSignalFirstEnumeratedFlagValue, // OSF8_ENUMSIGNALFIRSTENUMERATEDFLAGVALUE,
	&TestSimpleFlags8_EnumSignalLastEnumeratedFlagValue, // OSF8_ENUMSIGNALLASTENUMERATEDFLAGVALUE,
	&TestSimpleFlags8_EnumGetEnumeratedFlagValue, // OSF8_ENUMGETENUMERATEDFLAGVALUE,
	&TestSimpleFlags8_EnumFindFirstEnumeratedFlag, // OSF8_ENUMFINDFIRSTENUMERATEDFLAG,
	&TestSimpleFlags8_EnumAllSignalEnumeratedFlags, // OSF8_ENUMALLSIGNALENUMERATEDFLAGS,
	&TestSimpleFlags8_EnumAllDropEnumeratedFlags, // OSF8_ENUMALLDROPENUMERATEDFLAGS,
	&TestSimpleFlags8_EnumAllQueryEnumeratedFlags, // OSF8_ENUMALLQUERYENUMERATEDFLAGS,
	&TestSimpleFlags8_EnumAnyGetEnumeratedFlagValue, // OSF8_ENUMANYGETENUMERATEDFLAGVALUE,
	&TestSimpleFlags8_StoreFlagsEnumeratedValue, // OSF8_STOREFLAGSENUMERATEDVALUE,
	&TestSimpleFlags8_RetrieveFlagsEnumeratedValue, // OSF8_RETRIEVEFLAGSENUMERATEDVALUE,
};
static const CEnumUnsortedElementArray<EOUSIMPLEFLAGSFEATURE8, OSF8__MAX, CFeatureTestProcedure> g_afnSimpleFlags8FeatureTestProcedures;

template<>
const char *const CEnumUnsortedElementArray<EOUSIMPLEFLAGSFEATURE8, OSF8__MAX, const char *>::m_aetElementArray[] =
{
	"Constructors", // OSF8_CONSTRUCTORS
	"AssignFlagsAllValues", // OSF8_ASSIGNFLAGSALLVALUES,
	"QueryFlagsAllValues", // OSF8_QUERYFLAGSALLVALUES,
	"SetFlagsMaskValue", // OSF8_SETFLAGSMASKVALUE,
	"SignalFlagsMaskValue", // OSF8_SIGNALFLAGSMASKVALUE,
	"DropFlagsMaskValue", // OSF8_DROPFLAGSMASKVALUE,
	"ToggleSingleFlagValue", // OSF8_TOGGLESINGLEFLAGVALUE,
	"ModifySingleFlagValue", // OSF8_MODIFYSINGLEFLAGVALUE,
	"AssignFlagsByMask", // OSF8_ASSIGNFLAGSBYMASK,
	"AlterFlagsByMask", // OSF8_ALTERFLAGSBYMASK,
	"GetFlagsMaskValue", // OSF8_GETFLAGSMASKVALUE,
	"QueryFlagsByMask", // OSF8_QUERYFLAGSBYMASK,
	"OnlySignalSingleFlagOutOfMask", // OSF8_ONLYSIGNALSINGLEFLAGOUTOFMASK,
	"EnumSetEnumeratedFlagValue", // OSF8_ENUMSETENUMERATEDFLAGVALUE,
	"EnumSignalEnumeratedFlagValue", // OSF8_ENUMSIGNALENUMERATEDFLAGVALUE,
	"EnumDropEnumeratedFlagValue", // OSF8_ENUMDROPENUMERATEDFLAGVALUE,
	"EnumToggleEnumeratedFlagValue", // OSF8_ENUMTOGGLEENUMERATEDFLAGVALUE,
	"EnumModifyEnumeratedFlagValue", // OSF8_ENUMMODIFYENUMERATEDFLAGVALUE,
	"EnumSignalFirstEnumeratedFlagValue", // OSF8_ENUMSIGNALFIRSTENUMERATEDFLAGVALUE,
	"EnumSignalLastEnumeratedFlagValue", // OSF8_ENUMSIGNALLASTENUMERATEDFLAGVALUE,
	"EnumGetEnumeratedFlagValue", // OSF8_ENUMGETENUMERATEDFLAGVALUE,
	"EnumFindFirstEnumeratedFlag", // OSF8_ENUMFINDFIRSTENUMERATEDFLAG,
	"EnumAllSignalEnumeratedFlags", // OSF8_ENUMALLSIGNALENUMERATEDFLAGS,
	"EnumAllDropEnumeratedFlags", // OSF8_ENUMALLDROPENUMERATEDFLAGS,
	"EnumAllQueryEnumeratedFlags", // OSF8_ENUMALLQUERYENUMERATEDFLAGS,
	"EnumAnyGetEnumeratedFlagValue", // OSF8_ENUMANYGETENUMERATEDFLAGVALUE,
	"StoreFlagsEnumeratedValue", // OSF8_STOREFLAGSENUMERATEDVALUE,
	"RetrieveFlagsEnumeratedValue", // OSF8_RETRIEVEFLAGSENUMERATEDVALUE,
};
static const CEnumUnsortedElementArray<EOUSIMPLEFLAGSFEATURE8, OSF8__MAX, const char *> g_aszSimpleFlags8FeatureTestNames;


bool TestSimpleFlags8(unsigned int &nOutSuccessCount, unsigned int &nOutTestCount)
{
	return TestSubsystem(nOutSuccessCount, nOutTestCount, OSF8__MAX, g_aszSimpleFlags8FeatureTestNames.GetStoragePointer(), g_afnSimpleFlags8FeatureTestProcedures.GetStoragePointer());
}


//////////////////////////////////////////////////////////////////////////

bool TestFlagsDefines_EnumFlagsMask()
{
	bool bResult = false;
	
	do
	{
		int64ou iMask;
		
		iMask = OU_FLAGS_ENUMFLAGS_MASK(uint8ou, 1, 1);
		if (iMask - 1 != 0)
		{
			break;
		}
	
		iMask = OU_FLAGS_ENUMFLAGS_MASK(uint8ou, 1, OU_UINT8_BITS);
		if (iMask ^ OU_UINT8_MAX)
		{
			break;
		}

		iMask = OU_FLAGS_ENUMFLAGS_MASK(uint16ou, 1, 1);
		if (iMask - 1 != 0)
		{
			break;
		}
		
		iMask = OU_FLAGS_ENUMFLAGS_MASK(uint16ou, 1, OU_UINT16_BITS);
		if (iMask ^ OU_UINT16_MAX)
		{
			break;
		}
		
		iMask = OU_FLAGS_ENUMFLAGS_MASK(uint32ou, 1, 1);
		if (iMask - 1 != 0)
		{
			break;
		}
		
		iMask = OU_FLAGS_ENUMFLAGS_MASK(uint32ou, 1, OU_UINT32_BITS);
		if (iMask ^ OU_UINT32_MAX)
		{
			break;
		}
		
		iMask = OU_FLAGS_ENUMFLAGS_MASK(uint64ou, 1, 1);
		if (iMask - 1 != 0)
		{
			break;
		}
		
		iMask = OU_FLAGS_ENUMFLAGS_MASK(uint64ou, 1, OU_UINT64_BITS);
		if (iMask ^ OU_UINT64_MAX)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestFlagsDefines_EnumFlagsStartValid()
{
	bool bResult = false;
	
	do
	{
		if (!OU_FLAGS_ENUMFLAGS_START_VALID(uint8ou, 1, OU_UINT8_BITS))
		{
			break;
		}
/*	
		if (OU_FLAGS_ENUMFLAGS_START_VALID(uint8ou, 1, OU_UINT8_BITS + 1))
		{
			break;
		}
*/		
		if (!OU_FLAGS_ENUMFLAGS_START_VALID(uint16ou, 1, OU_UINT16_BITS))
		{
			break;
		}
/*		
		if (OU_FLAGS_ENUMFLAGS_START_VALID(uint16ou, 1, OU_UINT16_BITS + 1))
		{
			break;
		}
*/		
		if (!OU_FLAGS_ENUMFLAGS_START_VALID(uint32ou, 1, OU_UINT32_BITS))
		{
			break;
		}
/*		
		if (OU_FLAGS_ENUMFLAGS_START_VALID(uint32ou, 1, OU_UINT32_BITS + 1))
		{
			break;
		}
*/		
		if (!OU_FLAGS_ENUMFLAGS_START_VALID(uint64ou, 1, OU_UINT64_BITS))
		{
			break;
		}
/*		
		if (OU_FLAGS_ENUMFLAGS_START_VALID(uint64ou, 1, OU_UINT64_BITS + 1))
		{
			break;
		}
*/		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestFlagsDefines_StoreEnumValueInMask()
{
	bool bResult = false;
	
	do
	{
		if (!OU_FLAGS_STOREENUM_VALUE_IN_MASK(uint8ou, 0, 1) || !OU_FLAGS_STOREENUM_VALUE_IN_MASK(uint8ou, 1, 1))
		{
			break;
		}

		if (!OU_FLAGS_STOREENUM_VALUE_IN_MASK(uint8ou, 0, OU_UINT8_MAX) || !OU_FLAGS_STOREENUM_VALUE_IN_MASK(uint8ou, OU_UINT8_MAX, OU_UINT8_MAX))
		{
			break;
		}

		if (OU_FLAGS_STOREENUM_VALUE_IN_MASK(uint8ou, 1, 2) || OU_FLAGS_STOREENUM_VALUE_IN_MASK(uint8ou, 2, 1))
		{
			break;
		}

		if (OU_FLAGS_STOREENUM_VALUE_IN_MASK(uint8ou, 0, 0) || OU_FLAGS_STOREENUM_VALUE_IN_MASK(uint8ou, 1, 0))
		{
			break;
		}
	
		if (!OU_FLAGS_STOREENUM_VALUE_IN_MASK(uint16ou, 0, 1) || !OU_FLAGS_STOREENUM_VALUE_IN_MASK(uint16ou, 1, 1))
		{
			break;
		}
		
		if (!OU_FLAGS_STOREENUM_VALUE_IN_MASK(uint16ou, 0, OU_UINT16_MAX) || !OU_FLAGS_STOREENUM_VALUE_IN_MASK(uint16ou, OU_UINT16_MAX, OU_UINT16_MAX))
		{
			break;
		}
		
		if (OU_FLAGS_STOREENUM_VALUE_IN_MASK(uint16ou, 1, 2) || OU_FLAGS_STOREENUM_VALUE_IN_MASK(uint16ou, 2, 1))
		{
			break;
		}
		
		if (OU_FLAGS_STOREENUM_VALUE_IN_MASK(uint16ou, 0, 0) || OU_FLAGS_STOREENUM_VALUE_IN_MASK(uint16ou, 1, 0))
		{
			break;
		}
		
		if (!OU_FLAGS_STOREENUM_VALUE_IN_MASK(uint32ou, 0, 1) || !OU_FLAGS_STOREENUM_VALUE_IN_MASK(uint32ou, 1, 1))
		{
			break;
		}
		
		if (!OU_FLAGS_STOREENUM_VALUE_IN_MASK(uint32ou, 0, OU_UINT32_MAX) || !OU_FLAGS_STOREENUM_VALUE_IN_MASK(uint32ou, OU_UINT32_MAX, OU_UINT32_MAX))
		{
			break;
		}
		
		if (OU_FLAGS_STOREENUM_VALUE_IN_MASK(uint32ou, 1, 2) || OU_FLAGS_STOREENUM_VALUE_IN_MASK(uint32ou, 2, 1))
		{
			break;
		}
		
		if (OU_FLAGS_STOREENUM_VALUE_IN_MASK(uint32ou, 0, 0) || OU_FLAGS_STOREENUM_VALUE_IN_MASK(uint32ou, 1, 0))
		{
			break;
		}
		
		if (!OU_FLAGS_STOREENUM_VALUE_IN_MASK(uint64ou, 0, 1) || !OU_FLAGS_STOREENUM_VALUE_IN_MASK(uint64ou, 1, 1))
		{
			break;
		}
		
		if (!OU_FLAGS_STOREENUM_VALUE_IN_MASK(uint64ou, 0, OU_UINT64_MAX) || !OU_FLAGS_STOREENUM_VALUE_IN_MASK(uint64ou, OU_UINT64_MAX, OU_UINT64_MAX))
		{
			break;
		}
		
		if (OU_FLAGS_STOREENUM_VALUE_IN_MASK(uint64ou, 1, 2) || OU_FLAGS_STOREENUM_VALUE_IN_MASK(uint64ou, 2, 1))
		{
			break;
		}
		
		if (OU_FLAGS_STOREENUM_VALUE_IN_MASK(uint64ou, 0, 0) || OU_FLAGS_STOREENUM_VALUE_IN_MASK(uint64ou, 1, 0))
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

bool TestFlagsDefines_FlagIsSingle()
{
	bool bResult = false;
	
	do
	{
		if (!OU_FLAGS_FLAG_IS_SINGLE(uint8ou, 1) || !OU_FLAGS_FLAG_IS_SINGLE(uint8ou, OU_INT8_MIN))
		{
			break;
		}

		if (OU_FLAGS_FLAG_IS_SINGLE(uint8ou, 0) || OU_FLAGS_FLAG_IS_SINGLE(uint8ou, 3) || OU_FLAGS_FLAG_IS_SINGLE(uint8ou, OU_INT8_MIN + 1))
		{
			break;
		}
	
		if (!OU_FLAGS_FLAG_IS_SINGLE(uint16ou, 1) || !OU_FLAGS_FLAG_IS_SINGLE(uint16ou, OU_INT16_MIN))
		{
			break;
		}
		
		if (OU_FLAGS_FLAG_IS_SINGLE(uint16ou, 0) || OU_FLAGS_FLAG_IS_SINGLE(uint16ou, 3) || OU_FLAGS_FLAG_IS_SINGLE(uint16ou, OU_INT16_MIN + 1))
		{
			break;
		}
		
		if (!OU_FLAGS_FLAG_IS_SINGLE(uint32ou, 1) || !OU_FLAGS_FLAG_IS_SINGLE(uint32ou, OU_INT32_MIN))
		{
			break;
		}
		
		if (OU_FLAGS_FLAG_IS_SINGLE(uint32ou, 0) || OU_FLAGS_FLAG_IS_SINGLE(uint32ou, 3) || OU_FLAGS_FLAG_IS_SINGLE(uint32ou, OU_INT32_MIN + 1))
		{
			break;
		}
		
		if (!OU_FLAGS_FLAG_IS_SINGLE(uint64ou, 1) || !OU_FLAGS_FLAG_IS_SINGLE(uint64ou, OU_INT64_MIN))
		{
			break;
		}
		
		if (OU_FLAGS_FLAG_IS_SINGLE(uint64ou, 0) || OU_FLAGS_FLAG_IS_SINGLE(uint64ou, 3) || OU_FLAGS_FLAG_IS_SINGLE(uint64ou, OU_INT64_MIN + 1))
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}


enum EOUFLAGSDEFINESFEATURE
{
	OFF__MIN,
	
	OFF_ENUMFLAGS_MASK = OFF__MIN,
	OFF_ENUMFLAGS_START_VALID,
	OFF_STOREENUM_VALUE_IN_MASK,
	OFF_FLAG_IS_SINGLE,
	
	OFF__MAX,
};

template<>
CFeatureTestProcedure const CEnumUnsortedElementArray<EOUFLAGSDEFINESFEATURE, OFF__MAX, CFeatureTestProcedure>::m_aetElementArray[] =
{
	&TestFlagsDefines_EnumFlagsMask, // OFF_ENUMFLAGS_MASK,
	&TestFlagsDefines_EnumFlagsStartValid, // OFF_ENUMFLAGS_START_VALID,
	&TestFlagsDefines_StoreEnumValueInMask, // OFF_STOREENUM_VALUE_IN_MASK,
	&TestFlagsDefines_FlagIsSingle, // OFF_FLAG_IS_SINGLE,
};
static const CEnumUnsortedElementArray<EOUFLAGSDEFINESFEATURE, OFF__MAX, CFeatureTestProcedure> g_afnFlagsDefineFeatureTestProcedures;

template<>const char *const CEnumUnsortedElementArray<EOUFLAGSDEFINESFEATURE, OFF__MAX, const char *>::m_aetElementArray[] =
{
	"ENUMFLAGS_MASK", // OFF_ENUMFLAGS_MASK = OFF__MIN,
	"ENUMFLAGS_START_VALID", // OFF_ENUMFLAGS_START_VALID,
	"STOREENUM_VALUE_IN_MASK", // OFF_STOREENUM_VALUE_IN_MASK,
	"FLAG_IS_SINGLE", // OFF_FLAG_IS_SINGLE,
};
static const CEnumUnsortedElementArray<EOUFLAGSDEFINESFEATURE, OFF__MAX, const char *> g_aszFlagsDefineFeatureTestNames;


bool TestFlagsDefines(unsigned int &nOutSuccessCount, unsigned int &nOutTestCount)
{
	return TestSubsystem(nOutSuccessCount, nOutTestCount, OFF__MAX, g_aszFlagsDefineFeatureTestNames.GetStoragePointer(), g_afnFlagsDefineFeatureTestProcedures.GetStoragePointer());
}


//////////////////////////////////////////////////////////////////////////

enum EENUMARRAYTESTENUM
{
	ATE__MIN,

	ATE_FIRSTELEMENT = ATE__MIN,
	ATE_SECONDELEMENT,
	ATE_THIRDELEMENT,

	ATE__MAX,
};

template<>
const int CEnumUnsortedElementArray<EENUMARRAYTESTENUM, ATE__MAX, int>::m_aetElementArray[] =
{
	1, // ATE_FIRSTELEMENT,
	3, // ATE_SECONDELEMENT,
	2, // ATE_THIRDELEMENT,
};
static const CEnumUnsortedElementArray<EENUMARRAYTESTENUM, ATE__MAX, int> g_ai_IntUnsortedArray;

template<>
const int CEnumSortedElementArray<EENUMARRAYTESTENUM, ATE__MAX, int>::m_aetElementArray[] =
{
	1, // ATE_FIRSTELEMENT,
	2, // ATE_SECONDELEMENT,
	3, // ATE_THIRDELEMENT,
};
static const CEnumSortedElementArray<EENUMARRAYTESTENUM, ATE__MAX, int> g_ai_IntSortedArray;

struct ConstCharPtrEq
{
	bool operator ()(const char *szLeftValue, const char *szRightValue) const
	{
		return strcmp(szLeftValue, szRightValue) == 0;
	}
};

struct ConstCharPtrLess
{
	bool operator ()(const char *szLeftValue, const char *szRightValue) const
	{
		return strcmp(szLeftValue, szRightValue) < 0;
	}
};

template<>
const char *const CEnumUnsortedElementArray<EENUMARRAYTESTENUM, ATE__MAX, const char *, 0, ConstCharPtrEq>::m_aetElementArray[] =
{
	"first",
	"third",
	"second",
};
static const CEnumUnsortedElementArray<EENUMARRAYTESTENUM, ATE__MAX, const char *, 0, ConstCharPtrEq> g_aszStringUnsortedArray;

template<>
const char *const CEnumSortedElementArray<EENUMARRAYTESTENUM, ATE__MAX, const char *, 0, ConstCharPtrLess>::m_aetElementArray[] =
{
	"first",
	"second",
	"third",
};
static const CEnumSortedElementArray<EENUMARRAYTESTENUM, ATE__MAX, const char *, 0, ConstCharPtrLess> g_aszStringSortedArray;


bool TestEnumArrays_UnsortedArray()
{
	EENUMARRAYTESTENUM teEnumCurrent = ATE__MIN;
	
	for (; teEnumCurrent != ATE__MAX; ++teEnumCurrent)
	{
		int iCurrentValue = g_ai_IntUnsortedArray.Encode(teEnumCurrent);
		EENUMARRAYTESTENUM teIntDecodeCheck = g_ai_IntUnsortedArray.Decode(iCurrentValue);
		
		if (!g_ai_IntUnsortedArray.IsValidDecode(teIntDecodeCheck) || teIntDecodeCheck != teEnumCurrent)
		{
			break;
		}

		if (g_ai_IntUnsortedArray.GetStoragePointer()[teEnumCurrent] != iCurrentValue)
		{
			break;
		}

		const char *szCurrentString = g_aszStringUnsortedArray.Encode(teEnumCurrent);
		EENUMARRAYTESTENUM teStringDecodeCheck = g_aszStringUnsortedArray.Decode(szCurrentString);
		
		if (!g_aszStringUnsortedArray.IsValidDecode(teStringDecodeCheck) || teStringDecodeCheck != teEnumCurrent)
		{
			break;
		}

		if (strcmp(g_aszStringUnsortedArray.GetStoragePointer()[teEnumCurrent], szCurrentString) != 0)
		{
			break;
		}

		EENUMARRAYTESTENUM teInvalidDecodeCheck = g_aszStringUnsortedArray.Decode(szCurrentString + 1);
		if (teInvalidDecodeCheck != ATE__MAX || g_aszStringUnsortedArray.IsValidDecode(teInvalidDecodeCheck))
		{
			break;
		}
	}

	bool bResult = teEnumCurrent == ATE__MAX;
	return bResult;
}

bool TestEnumArrays_SortedArray()
{
	EENUMARRAYTESTENUM teEnumCurrent = ATE__MIN;
	
	for (; teEnumCurrent != ATE__MAX; ++teEnumCurrent)
	{
		int iCurrentValue = g_ai_IntSortedArray.Encode(teEnumCurrent);
		EENUMARRAYTESTENUM teIntDecodeCheck = g_ai_IntSortedArray.Decode(iCurrentValue);
		
		if (!g_ai_IntSortedArray.IsValidDecode(teIntDecodeCheck) || teIntDecodeCheck != teEnumCurrent)
		{
			break;
		}

		if (g_ai_IntSortedArray.GetStoragePointer()[teEnumCurrent] != iCurrentValue)
		{
			break;
		}

		const char *szCurrentString = g_aszStringSortedArray.Encode(teEnumCurrent);
		EENUMARRAYTESTENUM teStringDecodeCheck = g_aszStringSortedArray.Decode(szCurrentString);
		
		if (!g_aszStringSortedArray.IsValidDecode(teStringDecodeCheck) || teStringDecodeCheck != teEnumCurrent)
		{
			break;
		}

		if (strcmp(g_aszStringSortedArray.GetStoragePointer()[teEnumCurrent], szCurrentString) != 0)
		{
			break;
		}

		EENUMARRAYTESTENUM teInvalidDecodeCheck = g_aszStringSortedArray.Decode(szCurrentString + 1);
		if (teInvalidDecodeCheck != ATE__MAX || g_aszStringSortedArray.IsValidDecode(teInvalidDecodeCheck))
		{
			break;
		}
	}

	bool bResult = teEnumCurrent == ATE__MAX;
	return bResult;
}


enum EOUENUMARRAYSFEATURE
{
	ORF__MIN,

	ORF_UNSORTEDARRAY = ORF__MIN,
	ORF_SORTEDARRAY,

	ORF__MAX,
};

template<>
CFeatureTestProcedure const CEnumUnsortedElementArray<EOUENUMARRAYSFEATURE, ORF__MAX, CFeatureTestProcedure>::m_aetElementArray[] =
{
	&TestEnumArrays_UnsortedArray, // ORF_UNSORTEDARRAY,
	&TestEnumArrays_SortedArray, // ORF_SORTEDARRAY,
};
static const CEnumUnsortedElementArray<EOUENUMARRAYSFEATURE, ORF__MAX, CFeatureTestProcedure> g_afnEnumArrayFeatureTestProcedures;

template<>
const char *const CEnumUnsortedElementArray<EOUENUMARRAYSFEATURE, ORF__MAX, const char *>::m_aetElementArray[] =
{
	"Unsorted Array", // ORF_UNSORTEDARRAY,
	"Sorted Array", // ORF_SORTEDARRAY,
};
static const CEnumUnsortedElementArray<EOUENUMARRAYSFEATURE, ORF__MAX, const char *> g_aszEnumArrayFeatureTestNames;


bool TestEnumArrays(unsigned int &nOutSuccessCount, unsigned int &nOutTestCount)
{
	return TestSubsystem(nOutSuccessCount, nOutTestCount, ORF__MAX, g_aszEnumArrayFeatureTestNames.GetStoragePointer(), g_afnEnumArrayFeatureTestProcedures.GetStoragePointer());
}


//////////////////////////////////////////////////////////////////////////

enum ETESTTEMPLATES8
{
	TT8_ONE,
	TT8_TWO,
};

enum ETESTTEMPLATES16
{
	TT16_ONE = 1000,
	TT16_TWO,
};

enum ETESTTEMPLATES32
{
	TT32_ONE = 100000,
	TT32_TWO,
};


bool TestTemplates_PrefixIncrement()
{
	bool bResult = false;

	do
	{
		ETESTTEMPLATES8 t8Test = TT8_ONE;
		ETESTTEMPLATES16 t16Test = TT16_ONE;
		ETESTTEMPLATES32 t32Test = TT32_ONE;

		if (++t8Test != TT8_TWO || t8Test != TT8_TWO)
		{
			break;
		}

		++t8Test = TT8_ONE;
		if (t8Test != TT8_ONE)
		{
			break;
		}

		if (++t16Test != TT16_TWO || t16Test != TT16_TWO)
		{
			break;
		}

		++t16Test = TT16_ONE;
		if (t16Test != TT16_ONE)
		{
			break;
		}

		if (++t32Test != TT32_TWO || t32Test != TT32_TWO)
		{
			break;
		}

		++t32Test = TT32_ONE;
		if (t32Test != TT32_ONE)
		{
			break;
		}

		bResult = true;
	}
	while (false);

	return bResult;
}

bool TestTemplates_PostfixIncrement()
{
	bool bResult = false;

	do
	{
		ETESTTEMPLATES8 t8Test = TT8_ONE;
		ETESTTEMPLATES16 t16Test = TT16_ONE;
		ETESTTEMPLATES32 t32Test = TT32_ONE;

		if (t8Test++ != TT8_ONE || t8Test != TT8_TWO)
		{
			break;
		}

		if (t16Test++ != TT16_ONE || t16Test != TT16_TWO)
		{
			break;
		}

		if (t32Test++ != TT32_ONE || t32Test != TT32_TWO)
		{
			break;
		}

		bResult = true;
	}
	while (false);

	return bResult;
}

bool TestTemplates_PrefixDecrement()
{
	bool bResult = false;

	do
	{
		ETESTTEMPLATES8 t8Test = TT8_TWO;
		ETESTTEMPLATES16 t16Test = TT16_TWO;
		ETESTTEMPLATES32 t32Test = TT32_TWO;

		if (--t8Test != TT8_ONE || t8Test != TT8_ONE)
		{
			break;
		}

		--t8Test = TT8_TWO;
		if (t8Test != TT8_TWO)
		{
			break;
		}

		if (--t16Test != TT16_ONE || t16Test != TT16_ONE)
		{
			break;
		}

		--t16Test = TT16_TWO;
		if (t16Test != TT16_TWO)
		{
			break;
		}

		if (--t32Test != TT32_ONE || t32Test != TT32_ONE)
		{
			break;
		}

		--t32Test = TT32_TWO;
		if (t32Test != TT32_TWO)
		{
			break;
		}

		bResult = true;
	}
	while (false);

	return bResult;
}

bool TestTemplates_PostfixDecrement()
{
	bool bResult = false;

	do
	{
		ETESTTEMPLATES8 t8Test = TT8_TWO;
		ETESTTEMPLATES16 t16Test = TT16_TWO;
		ETESTTEMPLATES32 t32Test = TT32_TWO;

		if (t8Test-- != TT8_TWO || t8Test != TT8_ONE)
		{
			break;
		}

		if (t16Test-- != TT16_TWO || t16Test != TT16_ONE)
		{
			break;
		}

		if (t32Test-- != TT32_TWO || t32Test != TT32_ONE)
		{
			break;
		}

		bResult = true;
	}
	while (false);

	return bResult;
}

bool TestTemplates_IsEmptySz()
{
	bool bResult = false;

	do
	{
		const char *szData = "a";
		const char *szEmpty = "";
		const char *szNull = NULL;

		if (IsEmptySz(szData) || !IsEmptySz(szEmpty) || !IsEmptySz(szNull))
		{
			break;
		}

		bResult = true;
	}
	while (false);

	return bResult;
}


enum EOUTEMPLATESFEATURE
{
	OTF__MIN,

	OTF_PREFIXINCREMENT = OTF__MIN,
	OTF_POSTFIXINCREMENT,
	OTF_PREFIXDECREMENT,
	OTF_POSTFIXDECREMENT,
	OTF_ISEMPTYSZ,

	OTF__MAX,
};

template<>
CFeatureTestProcedure const CEnumUnsortedElementArray<EOUTEMPLATESFEATURE, OTF__MAX, CFeatureTestProcedure>::m_aetElementArray[] =
{
	&TestTemplates_PrefixIncrement, // OTF_PREFIXINCREMENT,
	&TestTemplates_PostfixIncrement, // OTF_POSTFIXINCREMENT,
	&TestTemplates_PrefixDecrement, // OTF_PREFIXDECREMENT,
	&TestTemplates_PostfixDecrement, // OTF_POSTFIXDECREMENT,
	&TestTemplates_IsEmptySz, // OTF_ISEMPTYSZ,
};
static const CEnumUnsortedElementArray<EOUTEMPLATESFEATURE, OTF__MAX, CFeatureTestProcedure> g_afnTemplateFeatureTestProcedures;

template<>
const char *const CEnumUnsortedElementArray<EOUTEMPLATESFEATURE, OTF__MAX, const char *>::m_aetElementArray[] =
{
	"Prefix Increment", // OTF_PREFIXINCREMENT,
	"Postfix Increment", // OTF_POSTFIXINCREMENT,
	"Prefix Decrement", // OTF_PREFIXDECREMENT,
	"Postfix Decrement", // OTF_POSTFIXDECREMENT,
	"IsEmptySz", // OTF_ISEMPTYSZ,
};
static const CEnumUnsortedElementArray<EOUTEMPLATESFEATURE, OTF__MAX, const char *> g_aszTemplateFeatureTestNames;


bool TestTemplates(unsigned int &nOutSuccessCount, unsigned int &nOutTestCount)
{
	return TestSubsystem(nOutSuccessCount, nOutTestCount, OTF__MAX, g_aszTemplateFeatureTestNames.GetStoragePointer(), g_afnTemplateFeatureTestProcedures.GetStoragePointer());
}


//////////////////////////////////////////////////////////////////////////

typedef CTypeSimpleWrapper<int> CTestWrapper;

bool TestTypeWrappers_Constructors()
{
	CTestWrapper twEmptyWrapper;
	CTestWrapper twZeroWrapper(0);
	CTestWrapper twCopyWrapper(twZeroWrapper);

	return true;
}

bool TestTypeWrappers_Comparison()
{
	bool bResult = false;

	do
	{
		CTestWrapper twOneWrapper(1);
		CTestWrapper twTwoWrapper(2);

		if (!(twTwoWrapper == twTwoWrapper) || twOneWrapper == twTwoWrapper)
		{
			break;
		}

		if (twTwoWrapper != twTwoWrapper || !(twOneWrapper != twTwoWrapper))
		{
			break;
		}

		if (!(twOneWrapper < twTwoWrapper) || twTwoWrapper < twTwoWrapper || twTwoWrapper < twOneWrapper)
		{
			break;
		}

		if (twOneWrapper > twTwoWrapper || twTwoWrapper > twTwoWrapper || !(twTwoWrapper > twOneWrapper))
		{
			break;
		}

		if (!(twOneWrapper <= twTwoWrapper) || !(twTwoWrapper <= twTwoWrapper) || twTwoWrapper <= twOneWrapper)
		{
			break;
		}

		if (twOneWrapper >= twTwoWrapper || !(twTwoWrapper >= twTwoWrapper) || !(twTwoWrapper >= twOneWrapper))
		{
			break;
		}

		bResult = true;
	}
	while (false);

	return bResult;
}

bool TestTypeWrappers_BoolCasts()
{
	bool bResult = false;

	do
	{
		CTestWrapper twZeroWrapper(0);
		CTestWrapper twOneWrapper(1);
/* -- cast to bool is commented in definition
		if (twZeroWrapper || !(false || twOneWrapper))
		{
			break;
		}
*/
		if (!(!twZeroWrapper) || !twOneWrapper)
		{
			break;
		}

		bResult = true;
	}
	while (false);

	return bResult;
}

bool TestTypeWrappers_Assignment()
{
	bool bResult = false;

	do
	{
		CTestWrapper twZeroWrapper(0);
		CTestWrapper twOneWrapper(1);

		CTestWrapper twTestWrapper;

		CTestWrapper &twFirstAssignmentReference = (twTestWrapper = (CTestWrapper::value_type)1);

		if (twTestWrapper != twOneWrapper || &twFirstAssignmentReference != &twTestWrapper)
		{
			break;
		}

		CTestWrapper &twSecondAssignmentReference = (twTestWrapper = twZeroWrapper);

		if (twTestWrapper != twZeroWrapper || &twSecondAssignmentReference != &twTestWrapper)
		{
			break;
		}

		bResult = true;
	}
	while (false);

	return bResult;
}

bool TestTypeWrappers_DataCast()
{
	bool bResult = false;

	do
	{
		const CTestWrapper twZeroWrapper(0);
		CTestWrapper twOneWrapper(1);

		const CTestWrapper::value_type &wtZeroValue = (const CTestWrapper::value_type &)twZeroWrapper;
		CTestWrapper::value_type &wtOneValue = (CTestWrapper::value_type &)twOneWrapper;

		if (wtZeroValue != 0 || wtOneValue != 1)
		{
			break;
		}

		wtOneValue = 0;

		if (twOneWrapper != twZeroWrapper)
		{
			break;
		}

		bResult = true;
	}
	while (false);

	return bResult;
}

bool TestTypeWrappers_DataComparison()
{
	bool bResult = false;

	do
	{
		const CTestWrapper twZeroWrapper(0);
		const CTestWrapper twOneWrapper(1);

		const CTestWrapper::value_type &wtZeroValue = twZeroWrapper;
		const CTestWrapper::value_type &wtOneValue = twOneWrapper;

		if (!(twZeroWrapper == wtZeroValue) || (twZeroWrapper == wtOneValue))
		{
			break;
		}

		if (!(wtZeroValue == twZeroWrapper) || (wtOneValue == twZeroWrapper))
		{
			break;
		}

		if ((twZeroWrapper != wtZeroValue) || !(twZeroWrapper != wtOneValue))
		{
			break;
		}

		if ((wtZeroValue != twZeroWrapper) || !(wtOneValue != twZeroWrapper))
		{
			break;
		}

		if ((twZeroWrapper < wtZeroValue) || !(twZeroWrapper < wtOneValue) || (twOneWrapper < wtZeroValue))
		{
			break;
		}

		if ((wtZeroValue < twZeroWrapper) || (wtOneValue < twZeroWrapper) || !(wtZeroValue < twOneWrapper))
		{
			break;
		}

		if ((twZeroWrapper > wtZeroValue) || (twZeroWrapper > wtOneValue) || !(twOneWrapper > wtZeroValue))
		{
			break;
		}

		if ((wtZeroValue > twZeroWrapper) || !(wtOneValue > twZeroWrapper) || (wtZeroValue > twOneWrapper))
		{
			break;
		}

		if (!(twZeroWrapper <= wtZeroValue) || !(twZeroWrapper <= wtOneValue) || (twOneWrapper <= wtZeroValue))
		{
			break;
		}

		if (!(wtZeroValue <= twZeroWrapper) || (wtOneValue <= twZeroWrapper) || !(wtZeroValue <= twOneWrapper))
		{
			break;
		}

		if (!(twZeroWrapper >= wtZeroValue) || (twZeroWrapper >= wtOneValue) || !(twOneWrapper >= wtZeroValue))
		{
			break;
		}

		if (!(wtZeroValue >= twZeroWrapper) || !(wtOneValue >= twZeroWrapper) || (wtZeroValue >= twOneWrapper))
		{
			break;
		}

		bResult = true;
	}
	while (false);

	return bResult;
}


enum EOUTYPEWRAPPERFEATURE
{
	OWF__MIN,

	OWF_CONSTRUCTORS = OWF__MIN,
	OWF_COMPARISON,
	OWF_BOOLCASTS,
	OWF_ASSIGNMENT,
	OWF_DATACAST,
	OWF_DATACOMPARISON,

	OWF__MAX,
};

template<>
CFeatureTestProcedure const CEnumUnsortedElementArray<EOUTYPEWRAPPERFEATURE, OWF__MAX, CFeatureTestProcedure>::m_aetElementArray[] =
{
	&TestTypeWrappers_Constructors, // OWF_CONSTRUCTORS,
	&TestTypeWrappers_Comparison, // OWF_COMPARISON,
	&TestTypeWrappers_BoolCasts, // OWF_BOOLCASTS,
	&TestTypeWrappers_Assignment, // OWF_ASSIGNMENT,
	&TestTypeWrappers_DataCast, // OWF_DATACAST,
	&TestTypeWrappers_DataComparison, // OWF_DATACOMPARISON,
};
static const CEnumUnsortedElementArray<EOUTYPEWRAPPERFEATURE, OWF__MAX, CFeatureTestProcedure> g_afnTypeWrapperFeatureTestProcedures;

template<>
const char *const CEnumUnsortedElementArray<EOUTYPEWRAPPERFEATURE, OWF__MAX, const char *>::m_aetElementArray[] =
{
	"Constructors", // OWF_CONSTRUCTORS,
	"Comparison Operators", // OWF_COMPARISON,
	"Boolean Casts", // OWF_BOOLCASTS,
	"Assignment Operators", // OWF_ASSIGNMENT,
	"Data Cast", // OWF_DATACAST,
	"Data Comparisons", // OWF_DATACOMPARISON,
};
static const CEnumUnsortedElementArray<EOUTYPEWRAPPERFEATURE, OWF__MAX, const char *> g_aszTypeWrapperFeatureTestNames;


bool TestTypeWrapper(unsigned int &nOutSuccessCount, unsigned int &nOutTestCount)
{
	return TestSubsystem(nOutSuccessCount, nOutTestCount, OWF__MAX, g_aszTypeWrapperFeatureTestNames.GetStoragePointer(), g_afnTypeWrapperFeatureTestProcedures.GetStoragePointer());
}


//////////////////////////////////////////////////////////////////////////

struct CTestCustomizations_Asserts_FailureInfo
{
	EASSERTIONFAILURESEVERITY m_fsFailureSeverity;
	const char *m_szAssertionExpression;
	const char *m_szAssertionFileName;
	unsigned int m_uiAssertionSourceLine;
};

static const CTestCustomizations_Asserts_FailureInfo g_fiAssertInvalidInfo = { AFS__MAX, NULL, NULL, 0  };
static CTestCustomizations_Asserts_FailureInfo g_fiAssertLastInfo;

void _OU_CONVENTION_CALLBACK TestCustomizations_Asserts_AssertionFailure(EASSERTIONFAILURESEVERITY fsFailureSeverity, 
	const char *szAssertionExpression, const char *szAssertionFileName, unsigned int uiAssertionSourceLine)
{
	g_fiAssertLastInfo.m_fsFailureSeverity = fsFailureSeverity;
	g_fiAssertLastInfo.m_szAssertionExpression = szAssertionExpression;
	g_fiAssertLastInfo.m_szAssertionFileName = szAssertionFileName;
	g_fiAssertLastInfo.m_uiAssertionSourceLine = uiAssertionSourceLine;
}


bool TestCustomizations_Asserts()
{
	bool bResult = false;

	CAssertionFailedProcedure fnAssertOldHandler = CAssertionCheckCustomization::GetAssertFailureCustomHandler();
	CAssertionCheckCustomization::CustomizeAssertionChecks(&TestCustomizations_Asserts_AssertionFailure);

	do
	{
#if !defined(NDEBUG)
		// Only callback invocation is checked here.
		// Availability of functionality depending on preprocessor defines
		// is verified in OST_ASSERT subsystem.

		OU_ASSERT(false); // const unsigned int uiAssertToVerifyLines = 14; -- see further in code

		if (g_fiAssertLastInfo.m_fsFailureSeverity != AFS_ASSERT
			|| g_fiAssertLastInfo.m_szAssertionExpression == NULL
			|| g_fiAssertLastInfo.m_szAssertionFileName == NULL
			|| strcmp(g_fiAssertLastInfo.m_szAssertionFileName, __FILE__) != 0
			|| g_fiAssertLastInfo.m_uiAssertionSourceLine == 0)
		{
			break;
		}

		CTestCustomizations_Asserts_FailureInfo fiAssertFailureInfoSave = g_fiAssertLastInfo;
		g_fiAssertLastInfo = g_fiAssertInvalidInfo;

		OU_VERIFY(false); const unsigned int uiAssertToVerifyLines = 14;

		if (g_fiAssertLastInfo.m_fsFailureSeverity != AFS_ASSERT
			|| g_fiAssertLastInfo.m_szAssertionExpression == NULL
			|| strcmp(g_fiAssertLastInfo.m_szAssertionExpression, fiAssertFailureInfoSave.m_szAssertionExpression) != 0
			|| g_fiAssertLastInfo.m_szAssertionFileName == NULL
			|| strcmp(g_fiAssertLastInfo.m_szAssertionFileName, __FILE__) != 0
			|| g_fiAssertLastInfo.m_uiAssertionSourceLine != fiAssertFailureInfoSave.m_uiAssertionSourceLine + uiAssertToVerifyLines)
		{
			break;
		}

		g_fiAssertLastInfo = g_fiAssertInvalidInfo;


#endif // #if !defined(NDEBUG)

/* -- can't verify OU_CHECK() as it crashes the application on failure
		OU_CHECK(false);

		if (g_fiAssertLastInfo.m_fsFailureSeverity != AFS_CHECK
			|| g_fiAssertLastInfo.m_szAssertionExpression == NULL
			|| g_fiAssertLastInfo.m_szAssertionFileName == NULL
			|| strcmp(g_fiAssertLastInfo.m_szAssertionFileName, __FILE__) != 0
			|| g_fiAssertLastInfo.m_uiAssertionSourceLine == 0)
		{
			break;
		}
*/
		bResult = true;
	}
	while (false);

	CAssertionCheckCustomization::CustomizeAssertionChecks(fnAssertOldHandler);

	return bResult;
}

void *const g_pv_MallocResult = (void *)(size_t)0x12345678;
bool g_bMallocInvocation = false, g_bReallocInvocation = false;
bool g_bFreeInvocation = false, g_bFreeSuccess = false;

void *_OU_CONVENTION_CALLBACK TestCustomizations_MemMgr_Alloc(size_t nBlockSize)
{
	g_bMallocInvocation = true;
	return (void *)((ptrdiff_t)g_pv_MallocResult + nBlockSize);
}

void *_OU_CONVENTION_CALLBACK TestCustomizations_MemMgr_Realloc(void *pv_OldBlock, size_t nBlockNewSize)
{
	g_bReallocInvocation = true;
	return (void *)((ptrdiff_t)pv_OldBlock - nBlockNewSize);
}

void _OU_CONVENTION_CALLBACK TestCustomizations_MemMgr_Free(void *pv_OldBlock)
{
	g_bFreeInvocation = true;
	g_bFreeSuccess = pv_OldBlock == g_pv_MallocResult;
}


bool TestCustomizations_MemMgr()
{
	bool bResult = false;

	CMemoryAllocationProcedure fnAllocationOldProcedure = CMemoryManagerCustomization::GetMemoryAllocationCustomProcedure();
	CMemoryReallocationProcedure fnReallocationOldProcedure = CMemoryManagerCustomization::GetMemoryReallocationCustomProcedure();
	CMemoryDeallocationProcedure fnDeallocationOldProcedure = CMemoryManagerCustomization::GetMemoryDeallocationCustomProcedure();
	CMemoryManagerCustomization::CustomizeMemoryManager(&TestCustomizations_MemMgr_Alloc, &TestCustomizations_MemMgr_Realloc, &TestCustomizations_MemMgr_Free);

	do
	{
		const size_t nBlockSize = 0x1000;

		void *pv_BlockAllocated = AllocateMemoryBlock(nBlockSize);

		if (!g_bMallocInvocation 
			|| pv_BlockAllocated != (void *)((size_t)g_pv_MallocResult + nBlockSize))
		{
			break;
		}

		void *pv_BlockReallocated = ReallocateMemoryBlock(pv_BlockAllocated, 2 * nBlockSize);

		if (!g_bReallocInvocation 
			|| pv_BlockReallocated != (void *)((size_t)g_pv_MallocResult - nBlockSize))
		{
			break;
		}

		FreeMemoryBlock(g_pv_MallocResult);

		if (!g_bFreeInvocation || !g_bFreeSuccess)
		{
			break;
		}

		bResult = true;
	}
	while (false);

	CMemoryManagerCustomization::CustomizeMemoryManager(fnAllocationOldProcedure, fnReallocationOldProcedure, fnDeallocationOldProcedure);

	return bResult;
}


enum EOUCUSTOMIZATIONFEATURE
{
	OCF__MIN,
		
	OCF_ASSERTS = OCF__MIN,
	OCF_MEMMGR,
		
	OCF__MAX,
};

template<>
CFeatureTestProcedure const CEnumUnsortedElementArray<EOUCUSTOMIZATIONFEATURE, OCF__MAX, CFeatureTestProcedure>::m_aetElementArray[] =
{
	&TestCustomizations_Asserts, // OCF_ASSERTS,
	&TestCustomizations_MemMgr, // OCF_MEMMGR,
};
static const CEnumUnsortedElementArray<EOUCUSTOMIZATIONFEATURE, OCF__MAX, CFeatureTestProcedure> g_afnCustomizationFeatureTestProcedures;

template<>
const char *const CEnumUnsortedElementArray<EOUCUSTOMIZATIONFEATURE, OCF__MAX, const char *>::m_aetElementArray[] =
{
	"Asserts", // OCF_ASSERTS,
	"Memory Manager", // OCF_MEMMGR,
};
static const CEnumUnsortedElementArray<EOUCUSTOMIZATIONFEATURE, OCF__MAX, const char *> g_aszCustomizationFeatureTestNames;


bool TestCustomization(unsigned int &nOutSuccessCount, unsigned int &nOutTestCount)
{
	return TestSubsystem(nOutSuccessCount, nOutTestCount, OCF__MAX, g_aszCustomizationFeatureTestNames.GetStoragePointer(), g_afnCustomizationFeatureTestProcedures.GetStoragePointer());
}


//////////////////////////////////////////////////////////////////////////

static const size_t g_nTestMallocBlockInitialSize = 1001;
static const size_t g_nTestMallocBlockNextSize = 65501;
static const uint8ou g_uiTestMallocToken = 0xAA;
static void *g_pv_MemoryBlock = NULL;

bool TestMallocs_Allocate()
{
	bool bResult = false;

	do
	{
		g_pv_MemoryBlock = AllocateMemoryBlock(g_nTestMallocBlockInitialSize);

		if (g_pv_MemoryBlock == NULL || OU_ALIGNED_SIZE((size_t)g_pv_MemoryBlock, _OU_MEMORY_REQUIRED_ALIGNMENT) != (size_t)g_pv_MemoryBlock)
		{
			break;
		}

		*((uint8ou *)g_pv_MemoryBlock + g_nTestMallocBlockInitialSize - 1) = g_uiTestMallocToken;
		
		bResult = true;
	}
	while (false);

	return bResult;
}

bool TestMallocs_Reallocate()
{
	OU_ASSERT(g_nTestMallocBlockNextSize > g_nTestMallocBlockInitialSize);

	bool bResult = false;

	do
	{
		void *pv_OldMemoryBlock = g_pv_MemoryBlock;
		g_pv_MemoryBlock = ReallocateMemoryBlock(pv_OldMemoryBlock, g_nTestMallocBlockNextSize);

		if (g_pv_MemoryBlock == NULL || OU_ALIGNED_SIZE((size_t)g_pv_MemoryBlock, _OU_MEMORY_REQUIRED_ALIGNMENT) != (size_t)g_pv_MemoryBlock)
		{
			break;
		}

		if (*((uint8ou *)g_pv_MemoryBlock + g_nTestMallocBlockInitialSize - 1) != g_uiTestMallocToken)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);

	return bResult;
}

bool TestMallocs_Deallocate()
{
	FreeMemoryBlock(g_pv_MemoryBlock);

	FreeMemoryBlock(NULL); // Free must survive NULL-pointer

	return true;
}


enum EOUMALLOCFEATURE
{
	OLF__MIN,
		
	OLF_ALLOCATE = OLF__MIN,
	OLF_REALLOCATE,
	OLF_DEALLOCATE,
		
	OLF__MAX,
};

template<>
CFeatureTestProcedure const CEnumUnsortedElementArray<EOUMALLOCFEATURE, OLF__MAX, CFeatureTestProcedure>::m_aetElementArray[] =
{
	&TestMallocs_Allocate, // OLF_ALLOCATE,
	&TestMallocs_Reallocate, // OLF_REALLOCATE,
	&TestMallocs_Deallocate, // OLF_DEALLOCATE,
};
static const CEnumUnsortedElementArray<EOUMALLOCFEATURE, OLF__MAX, CFeatureTestProcedure> g_afnMallocFeatureTestProcedures;

template<>
const char *const CEnumUnsortedElementArray<EOUMALLOCFEATURE, OLF__MAX, const char *>::m_aetElementArray[] =
{
	"AllocateMemoryBlock", // OLF_ALLOCATE,
	"ReallocateMemoryBlock", // OLF_REALLOCATE,
	"FreeMemoryBlock", // OLF_DEALLOCATE,
};
static const CEnumUnsortedElementArray<EOUMALLOCFEATURE, OLF__MAX, const char *> g_aszMallocFeatureTestNames;


bool TestMalloc(unsigned int &nOutSuccessCount, unsigned int &nOutTestCount)
{
	return TestSubsystem(nOutSuccessCount, nOutTestCount, OLF__MAX, g_aszMallocFeatureTestNames.GetStoragePointer(), g_afnMallocFeatureTestProcedures.GetStoragePointer());
}


//////////////////////////////////////////////////////////////////////////

bool TestAsserts_FalseFunction(bool &bVarInvocation)
{
	bool bResult = true;
	bVarInvocation = !bVarInvocation;

	bool *pv_Pointer = &bResult;
	if (pv_Pointer)
	{
		bResult = false;
	}

	return bResult;
}

bool TestAsserts_TrueFunction(bool &bVarInvocation)
{
	bool bResult = false;
	bVarInvocation = !bVarInvocation;
	
	bool *pv_Pointer = &bResult;
	if (pv_Pointer)
	{
		bResult = true;
	}
	
	return bResult;
}

bool TestAsserts_Assert()
{
	bool bNDebugInvocation = false, bOrdinaryInvocation = false;

#if defined(NDEBUG)
	
	OU_ASSERT(TestAsserts_FalseFunction(bNDebugInvocation));

	bOrdinaryInvocation = true;

#endif // #if defined(NDEBUG)
	
	OU_ASSERT(TestAsserts_TrueFunction(bOrdinaryInvocation));

	return !bNDebugInvocation && bOrdinaryInvocation;
}

bool TestAsserts_Verify()
{
	bool bNDebugInvocation = false, bOrdinaryInvocation = false;
	
#if defined(NDEBUG)
	
	OU_VERIFY(TestAsserts_FalseFunction(bNDebugInvocation));
	

#else // #if !defined(NDEBUG)

	bNDebugInvocation = true;


#endif // #if !defined(NDEBUG)
	
	OU_VERIFY(TestAsserts_TrueFunction(bOrdinaryInvocation));
	
	return bNDebugInvocation && bOrdinaryInvocation;
}

bool TestAsserts_Check()
{
	bool bOrdinaryInvocation = false;
	
	OU_CHECK(TestAsserts_TrueFunction(bOrdinaryInvocation));
	
	return bOrdinaryInvocation;
}


enum EOUASSERTFEATURE
{
	OEF__MIN,
		
	OEF_ASSERT = OEF__MIN,
	OEF_VERIFY,
	OEF_CHECK,
	
	OEF__MAX,
};

template<>
CFeatureTestProcedure const CEnumUnsortedElementArray<EOUASSERTFEATURE, OEF__MAX, CFeatureTestProcedure>::m_aetElementArray[] =
{
	&TestAsserts_Assert, // OEF_ASSERT,
	&TestAsserts_Verify, // OEF_VERIFY,
	&TestAsserts_Check, // OEF_CHECK,
		
};
static const CEnumUnsortedElementArray<EOUASSERTFEATURE, OEF__MAX, CFeatureTestProcedure> g_afnAssertFeatureTestProcedures;

template<>
const char *const CEnumUnsortedElementArray<EOUASSERTFEATURE, OEF__MAX, const char *>::m_aetElementArray[] =
{
	"OU_ASSERT", // OEF_ASSERT,
	"OU_VERIFY", // OEF_VERIFY,
	"OU_CHECK", // OEF_CHECK,
};
static const CEnumUnsortedElementArray<EOUASSERTFEATURE, OEF__MAX, const char *> g_aszAssertFeatureTestNames;


bool TestAssert(unsigned int &nOutSuccessCount, unsigned int &nOutTestCount)
{
	return TestSubsystem(nOutSuccessCount, nOutTestCount, OEF__MAX, g_aszAssertFeatureTestNames.GetStoragePointer(), g_afnAssertFeatureTestProcedures.GetStoragePointer());
}


//////////////////////////////////////////////////////////////////////////

struct CTestIntTypes_int8
{
	int8ou  m_iPad;
	int8ou	m_iValue;
};

bool TestIntTypes_Int8()
{
	bool bResult = false;
	
	do
	{
		if (sizeof(int8ou) != 1 || offsetof(CTestIntTypes_int8, m_iValue) != 1)
		{
			break;
		}

		if (OU_INT8_BITS != sizeof(int8ou) * OU_BITS_IN_BYTE )
		{
			break;
		}

		if ((int8ou)OU_INT8_MIN == 0 || (int8ou)(OU_INT8_MIN << 1) != 0)
		{
			break;
		}

		if (~OU_INT8_MIN != OU_INT8_MAX || ~OU_INT8_MAX != OU_INT8_MIN)
		{
			break;
		}

		bResult = true;
	}
	while (false);
	
	return bResult;
}

struct CTestIntTypes_uint8
{
	int8ou  m_iPad;
	uint8ou	m_iValue;
};

bool TestIntTypes_UInt8()
{
	bool bResult = false;
	
	do
	{
		if (sizeof(uint8ou) != 1 || offsetof(CTestIntTypes_uint8, m_iValue) != 1)
		{
			break;
		}

		if (OU_UINT8_BITS != sizeof(uint8ou) * OU_BITS_IN_BYTE)
		{
			break;
		}
		
		if (OU_UINT8_MIN != 0)
		{
			break;
		}

		if (!(OU_UINT8_MAX & (uint8ou)1) || (OU_UINT8_MAX >> 1) != (uint8ou)OU_INT8_MAX)
		{
			break;
		}
	
		bResult = true;
	}
	while (false);
	
	return bResult;
}

struct CTestIntTypes_int16
{
	int8ou  m_iPad;
	int16ou	m_iValue;
};

bool TestIntTypes_Int16()
{
	bool bResult = false;
	
	do
	{
		if (sizeof(int16ou) != 2 || offsetof(CTestIntTypes_int16, m_iValue) != 2)
		{
			break;
		}
		
		if (OU_INT16_BITS != sizeof(int16ou) * OU_BITS_IN_BYTE )
		{
			break;
		}
		
		if ((int16ou)OU_INT16_MIN == 0 || (int16ou)(OU_INT16_MIN << 1) != 0)
		{
			break;
		}
		
		if (~OU_INT16_MIN != OU_INT16_MAX || ~OU_INT16_MAX != OU_INT16_MIN)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

struct CTestIntTypes_uint16
{
	int8ou  m_iPad;
	uint16ou	m_iValue;
};

bool TestIntTypes_UInt16()
{
	bool bResult = false;
	
	do
	{
		if (sizeof(uint16ou) != 2 || offsetof(CTestIntTypes_uint16, m_iValue) != 2)
		{
			break;
		}
		
		if (OU_UINT16_BITS != sizeof(uint16ou) * OU_BITS_IN_BYTE)
		{
			break;
		}
		
		if (OU_UINT16_MIN != 0)
		{
			break;
		}
		
		if (!(OU_UINT16_MAX & (uint16ou)1) || (OU_UINT16_MAX >> 1) != (uint16ou)OU_INT16_MAX)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

struct CTestIntTypes_int32
{
	int8ou  m_iPad;
	int32ou	m_iValue;
};

bool TestIntTypes_Int32()
{
	bool bResult = false;
	
	do
	{
		if (sizeof(int32ou) != 4 || offsetof(CTestIntTypes_int32, m_iValue) != 4)
		{
			break;
		}
		
		if (OU_INT32_BITS != sizeof(int32ou) * OU_BITS_IN_BYTE )
		{
			break;
		}
		
		if ((int32ou)OU_INT32_MIN == 0 || (int32ou)(OU_INT32_MIN << 1) != 0)
		{
			break;
		}
		
		if (~OU_INT32_MIN != OU_INT32_MAX || ~OU_INT32_MAX != OU_INT32_MIN)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

struct CTestIntTypes_uint32
{
	int8ou  m_iPad;
	uint32ou	m_iValue;
};

bool TestIntTypes_UInt32()
{
	bool bResult = false;
	
	do
	{
		if (sizeof(uint32ou) != 4 || offsetof(CTestIntTypes_uint32, m_iValue) != 4)
		{
			break;
		}
		
		if (OU_UINT32_BITS != sizeof(uint32ou) * OU_BITS_IN_BYTE)
		{
			break;
		}
		
		if (OU_UINT32_MIN != 0)
		{
			break;
		}
		
		if (!(OU_UINT32_MAX & (uint32ou)1) || (OU_UINT32_MAX >> 1) != (uint32ou)OU_INT32_MAX)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

struct CTestIntTypes_int64
{
	int8ou  m_iPad;
	int64ou	m_iValue;
};

bool TestIntTypes_Int64()
{
	bool bResult = false;
	
	do
	{
		if (sizeof(int64ou) != 8)
		{
			break;
		}
		
#if _OU_TARGET_ARCH == _OU_TARGET_ARCH_X86 && _OU_TARGET_OS != _OU_TARGET_OS_MAC
		
		if (offsetof(CTestIntTypes_int64, m_iValue) != 8)
		{
			break;
		}


#endif

		if (OU_INT64_BITS != sizeof(int64ou) * OU_BITS_IN_BYTE )
		{
			break;
		}
		
		if ((int64ou)OU_INT64_MIN == 0 || (int64ou)(OU_INT64_MIN << 1) != 0)
		{
			break;
		}
		
		if (~OU_INT64_MIN != OU_INT64_MAX || ~OU_INT64_MAX != OU_INT64_MIN)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}

struct CTestIntTypes_uint64
{
	int8ou  m_iPad;
	uint64ou	m_iValue;
};

bool TestIntTypes_UInt64()
{
	bool bResult = false;
	
	do
	{
		if (sizeof(uint64ou) != 8)
		{
			break;
		}
		
#if _OU_TARGET_ARCH == _OU_TARGET_ARCH_X86 && _OU_TARGET_OS != _OU_TARGET_OS_MAC
		
		if (offsetof(CTestIntTypes_uint64, m_iValue) != 8)
		{
			break;
		}


#endif

		if (OU_UINT64_BITS != sizeof(uint64ou) * OU_BITS_IN_BYTE)
		{
			break;
		}
		
		if (OU_UINT64_MIN != 0)
		{
			break;
		}
		
		if (!(OU_UINT64_MAX & (uint64ou)1) || (OU_UINT64_MAX >> 1) != (uint64ou)OU_INT64_MAX)
		{
			break;
		}
		
		bResult = true;
	}
	while (false);
	
	return bResult;
}


enum EOUINTTYPEFEATURE
{
	OIF__MIN,
		
	OIF_INT8 = OIF__MIN,
	OIF_UINT8,
	OIF_INT16,
	OIF_UINT16,
	OIF_INT32,
	OIF_UINT32,
	OIF_INT64,
	OIF_UINT64,
	
	OIF__MAX,
};

template<>
CFeatureTestProcedure const CEnumUnsortedElementArray<EOUINTTYPEFEATURE, OIF__MAX, CFeatureTestProcedure>::m_aetElementArray[] =
{
	&TestIntTypes_Int8, // OIF_INT8,
	&TestIntTypes_UInt8, // OIF_UINT8,
	&TestIntTypes_Int16, // OIF_INT16,
	&TestIntTypes_UInt16, // OIF_UINT16,
	&TestIntTypes_Int32, // OIF_INT32,
	&TestIntTypes_UInt32, // OIF_UINT32,
	&TestIntTypes_Int64, // OIF_INT64,
	&TestIntTypes_UInt64, // OIF_UINT64,

};
static const CEnumUnsortedElementArray<EOUINTTYPEFEATURE, OIF__MAX, CFeatureTestProcedure> g_afnIntTypeFeatureTestProcedures;

template<>
const char *const CEnumUnsortedElementArray<EOUINTTYPEFEATURE, OIF__MAX, const char *>::m_aetElementArray[] =
{
	"int8ou", // OIF_INT8,
	"uint8ou", // OIF_UINT8,
	"int16ou", // OIF_INT16,
	"uint16ou", // OIF_UINT16,
	"int32ou", // OIF_INT32,
	"uint32ou", // OIF_UINT32,
	"int64ou", // OIF_INT64,
	"uint64ou", // OIF_UINT64,
};
static const CEnumUnsortedElementArray<EOUINTTYPEFEATURE, OIF__MAX, const char *> g_aszIntTypeFeatureTestNames;


bool TestIntTypes(unsigned int &nOutSuccessCount, unsigned int &nOutTestCount)
{
	return TestSubsystem(nOutSuccessCount, nOutTestCount, OIF__MAX, g_aszIntTypeFeatureTestNames.GetStoragePointer(), g_afnIntTypeFeatureTestProcedures.GetStoragePointer());
}


//////////////////////////////////////////////////////////////////////////

struct CTestMacros_OffsetStruct 
{
	int8ou		m_i8a;
	int16ou		m_i16a;
	int32ou		m_i32a;
	int64ou		m_i64;
	int32ou		m_i32b;
	int16ou		m_i16b;
	int8ou		m_i8b;
};

bool TestMacros_OffsetOf()
{
	size_t sOffset_i8a = offsetof(CTestMacros_OffsetStruct, m_i8a);
	size_t sOffset_i16a = offsetof(CTestMacros_OffsetStruct, m_i16a);
	size_t sOffset_i32a = offsetof(CTestMacros_OffsetStruct, m_i32a);
	size_t sOffset_i64 = offsetof(CTestMacros_OffsetStruct, m_i64);
	size_t sOffset_i32b = offsetof(CTestMacros_OffsetStruct, m_i32b);
	size_t sOffset_i16b = offsetof(CTestMacros_OffsetStruct, m_i16b);
	size_t sOffset_i8b = offsetof(CTestMacros_OffsetStruct, m_i8b);
	size_t sStructSize = sizeof(CTestMacros_OffsetStruct);

	return true
		&& sOffset_i8a == 0
		&& sOffset_i16a == 2
		&& sOffset_i32a == 4
		&& sOffset_i64 == 8
		&& sOffset_i32b == 16
		&& sOffset_i16b == 20
		&& sOffset_i8b == 22
		&& sStructSize == 24;
}

bool TestMacros_AlignedSize()
{
	return true
		&& OU_ALIGNED_SIZE(0, sizeof(int8ou)) == 0
		&& OU_ALIGNED_SIZE(0, sizeof(int16ou)) == 0
		&& OU_ALIGNED_SIZE(0, sizeof(int32ou)) == 0
		&& OU_ALIGNED_SIZE(0, sizeof(int64ou)) == 0
		&& OU_ALIGNED_SIZE(sizeof(int8ou), sizeof(int8ou)) == sizeof(int8ou)
		&& OU_ALIGNED_SIZE(sizeof(int8ou), sizeof(int16ou)) == sizeof(int16ou)
		&& OU_ALIGNED_SIZE(sizeof(int8ou), sizeof(int32ou)) == sizeof(int32ou)
		&& OU_ALIGNED_SIZE(sizeof(int8ou), sizeof(int64ou)) == sizeof(int64ou)
		&& OU_ALIGNED_SIZE(sizeof(int16ou), sizeof(int8ou)) == sizeof(int16ou)
		&& OU_ALIGNED_SIZE(sizeof(int16ou), sizeof(int16ou)) == sizeof(int16ou)
		&& OU_ALIGNED_SIZE(sizeof(int16ou), sizeof(int32ou)) == sizeof(int32ou)
		&& OU_ALIGNED_SIZE(sizeof(int16ou), sizeof(int64ou)) == sizeof(int64ou)
		&& OU_ALIGNED_SIZE(sizeof(int32ou), sizeof(int8ou)) == sizeof(int32ou)
		&& OU_ALIGNED_SIZE(sizeof(int32ou), sizeof(int16ou)) == sizeof(int32ou)
		&& OU_ALIGNED_SIZE(sizeof(int32ou), sizeof(int32ou)) == sizeof(int32ou)
		&& OU_ALIGNED_SIZE(sizeof(int32ou), sizeof(int64ou)) == sizeof(int64ou)
		&& OU_ALIGNED_SIZE(sizeof(int64ou), sizeof(int8ou)) == sizeof(int64ou)
		&& OU_ALIGNED_SIZE(sizeof(int64ou), sizeof(int16ou)) == sizeof(int64ou)
		&& OU_ALIGNED_SIZE(sizeof(int64ou), sizeof(int32ou)) == sizeof(int64ou)
		&& OU_ALIGNED_SIZE(sizeof(int64ou), sizeof(int64ou)) == sizeof(int64ou);
}

bool TestMacros_ArraySize()
{
	static int m_ai_Array1[1];
	static int m_aai_Array11[1][1];
	static int m_ai_Array2[2];
	static int m_aai_Array21[2][1];
	static int m_aai_Array12[1][2];

	return true
		&& OU_ARRAY_SIZE(m_ai_Array1) == 1
		&& OU_ARRAY_SIZE(m_aai_Array11[0]) == 1
		&& OU_ARRAY_SIZE(m_aai_Array11) == 1
		&& OU_ARRAY_SIZE(m_ai_Array2) == 2
		&& OU_ARRAY_SIZE(m_aai_Array21[0]) == 1
		&& OU_ARRAY_SIZE(m_aai_Array21) == 2
		&& OU_ARRAY_SIZE(m_aai_Array12[0]) == 2
		&& OU_ARRAY_SIZE(m_aai_Array12) == 1;
}

bool TestMacros_InIntRange()
{
	char iZero = 0;
	char iOne = 1;
	char iMinusOne = -1;
	unsigned int uiTen = 10;
	unsigned int uiNotZero = ~0U;

	return true
		&& !OU_IN_INT_RANGE(iZero, 0, 0)
		&& !OU_IN_INT_RANGE(iOne, 0, 0)
		&& !OU_IN_INT_RANGE(iMinusOne, 0, 0)
		&& !OU_IN_INT_RANGE(uiTen, 0, 0)
		&& !OU_IN_INT_RANGE(uiNotZero, 0, 0)

		&& OU_IN_INT_RANGE(iZero, 0, 1)
		&& !OU_IN_INT_RANGE(iOne, 0, 1)
		&& !OU_IN_INT_RANGE(iMinusOne, 0, 1)
		&& !OU_IN_INT_RANGE(uiTen, 0, 1)
		&& !OU_IN_INT_RANGE(uiNotZero, 0, 1)

		&& !OU_IN_INT_RANGE(iZero, 1, 2)
		&& OU_IN_INT_RANGE(iOne, 1, 2)
		&& !OU_IN_INT_RANGE(iMinusOne, 1, 2)
		&& !OU_IN_INT_RANGE(uiTen, 1, 2)
		&& !OU_IN_INT_RANGE(uiNotZero, 1, 2)

		&& OU_IN_INT_RANGE(iZero, -1, 1)
		&& !OU_IN_INT_RANGE(iOne, -1, 1)
		&& OU_IN_INT_RANGE(iMinusOne, -1, 1)
		&& !OU_IN_INT_RANGE(uiTen, -1, 1)
		&& OU_IN_INT_RANGE(uiNotZero, -1, 1)

		&& !OU_IN_INT_RANGE(iZero, 1, -1)
		&& OU_IN_INT_RANGE(iOne, 1, -1)
		&& !OU_IN_INT_RANGE(iMinusOne, 1, -1)
		&& OU_IN_INT_RANGE(uiTen, 1, -1)
		&& !OU_IN_INT_RANGE(uiNotZero, 1, -1);
}

bool TestMacros_InI64Range()
{
	char iZero = 0;
	char iOne = 1;
	char iMinusOne = -1;
	unsigned int uiTen = 10;
	unsigned int uiNotZero = ~0U;
	
	return true
		&& !OU_IN_I64_RANGE(iZero, 0, 0)
		&& !OU_IN_I64_RANGE(iOne, 0, 0)
		&& !OU_IN_I64_RANGE(iMinusOne, 0, 0)
		&& !OU_IN_I64_RANGE(uiTen, 0, 0)
		&& !OU_IN_I64_RANGE(uiNotZero, 0, 0)
		
		&& OU_IN_I64_RANGE(iZero, 0, 1)
		&& !OU_IN_I64_RANGE(iOne, 0, 1)
		&& !OU_IN_I64_RANGE(iMinusOne, 0, 1)
		&& !OU_IN_I64_RANGE(uiTen, 0, 1)
		&& !OU_IN_I64_RANGE(uiNotZero, 0, 1)
		
		&& !OU_IN_I64_RANGE(iZero, 1, 2)
		&& OU_IN_I64_RANGE(iOne, 1, 2)
		&& !OU_IN_I64_RANGE(iMinusOne, 1, 2)
		&& !OU_IN_I64_RANGE(uiTen, 1, 2)
		&& !OU_IN_I64_RANGE(uiNotZero, 1, 2)
		
		&& OU_IN_I64_RANGE(iZero, -1, 1)
		&& !OU_IN_I64_RANGE(iOne, -1, 1)
		&& OU_IN_I64_RANGE(iMinusOne, -1, 1)
		&& !OU_IN_I64_RANGE(uiTen, -1, 1)
		&& !OU_IN_I64_RANGE(uiNotZero, -1, 1)
		
		&& !OU_IN_I64_RANGE(iZero, 1, -1)
		&& OU_IN_I64_RANGE(iOne, 1, -1)
		&& !OU_IN_I64_RANGE(iMinusOne, 1, -1)
		&& OU_IN_I64_RANGE(uiTen, 1, -1)
		&& OU_IN_I64_RANGE(uiNotZero, 1, -1);
}

bool TestMacros_InSizetRange()
{
	char iZero = 0;
	char iOne = 1;
	char iMinusOne = -1;
	unsigned int uiTen = 10;
	unsigned int uiNotZero = ~0U;
	
	return true
		&& !OU_IN_SIZET_RANGE(iZero, 0, 0)
		&& !OU_IN_SIZET_RANGE(iOne, 0, 0)
		&& !OU_IN_SIZET_RANGE(iMinusOne, 0, 0)
		&& !OU_IN_SIZET_RANGE(uiTen, 0, 0)
		&& !OU_IN_SIZET_RANGE(uiNotZero, 0, 0)
		
		&& OU_IN_SIZET_RANGE(iZero, 0, 1)
		&& !OU_IN_SIZET_RANGE(iOne, 0, 1)
		&& !OU_IN_SIZET_RANGE(iMinusOne, 0, 1)
		&& !OU_IN_SIZET_RANGE(uiTen, 0, 1)
		&& !OU_IN_SIZET_RANGE(uiNotZero, 0, 1)
		
		&& !OU_IN_SIZET_RANGE(iZero, 1, 2)
		&& OU_IN_SIZET_RANGE(iOne, 1, 2)
		&& !OU_IN_SIZET_RANGE(iMinusOne, 1, 2)
		&& !OU_IN_SIZET_RANGE(uiTen, 1, 2)
		&& !OU_IN_SIZET_RANGE(uiNotZero, 1, 2)
		
		&& OU_IN_SIZET_RANGE(iZero, -1, 1)
		&& !OU_IN_SIZET_RANGE(iOne, -1, 1)
		&& OU_IN_SIZET_RANGE(iMinusOne, -1, 1)
		&& !OU_IN_SIZET_RANGE(uiTen, -1, 1)
		&& OU_IN_SIZET_RANGE(uiNotZero, -1, 1) == (sizeof(size_t) == sizeof(unsigned int))
		
		&& !OU_IN_SIZET_RANGE(iZero, 1, -1)
		&& OU_IN_SIZET_RANGE(iOne, 1, -1)
		&& !OU_IN_SIZET_RANGE(iMinusOne, 1, -1)
		&& OU_IN_SIZET_RANGE(uiTen, 1, -1)
		&& OU_IN_SIZET_RANGE(uiNotZero, 1, -1) != (sizeof(size_t) == sizeof(unsigned int));
}


enum EOUMACROFEATURE
{
	OMF__MIN,

	OMF_OFFSETOF = OMF__MIN,
	OMF_ALIGNEDSIZE,
	OMF_ARRAYSIZE,
	OMF_ININTRANGE,
	OMF_INI64RANGE,
	OMF_INSIZETRANGE,

	OMF__MAX,
};

template<>
CFeatureTestProcedure const CEnumUnsortedElementArray<EOUMACROFEATURE, OMF__MAX, CFeatureTestProcedure>::m_aetElementArray[] =
{
	&TestMacros_OffsetOf, // OMF_OFFSETOF,
	&TestMacros_AlignedSize, // OMF_ALIGNEDSIZE,
	&TestMacros_ArraySize, // OMF_ARRAYSIZE,
	&TestMacros_InIntRange, // OMF_ININTRANGE,
	&TestMacros_InI64Range, // OMF_INI64RANGE,
	&TestMacros_InSizetRange, // OMF_INSIZETRANGE,
};
static const CEnumUnsortedElementArray<EOUMACROFEATURE, OMF__MAX, CFeatureTestProcedure> g_afnMacroFeatureTestProcedures;

template<>
const char *const CEnumUnsortedElementArray<EOUMACROFEATURE, OMF__MAX, const char *>::m_aetElementArray[] =
{
	"offsetof", // OMF_OFFSETOF,
	"OU_ALIGNED_SIZE", // OMF_ALIGNEDSIZE,
	"OU_ARRAY_SIZE", // OMF_ARRAYSIZE,
	"OU_IN_INT_RANGE", // OMF_ININTRANGE,
	"OU_IN_I64_RANGE", // OMF_INI64RANGE,
	"OU_IN_SIZET_RANGE", // OMF_INSIZETRANGE,
};
static const CEnumUnsortedElementArray<EOUMACROFEATURE, OMF__MAX, const char *> g_aszMacroFeatureTestNames;


bool TestMacros(unsigned int &nOutSuccessCount, unsigned int &nOutTestCount)
{
	return TestSubsystem(nOutSuccessCount, nOutTestCount, OMF__MAX, g_aszMacroFeatureTestNames.GetStoragePointer(), g_afnMacroFeatureTestProcedures.GetStoragePointer());
}


//////////////////////////////////////////////////////////////////////////

// Verifies that target order is not changed
template<>
int const CEnumSortedElementArray<int, _OU_TARGET_OS__MAX - 1, int, 100>::m_aetElementArray[] =
{
	_OU_TARGET_OS_GENUNIX, // _OU_TARGET_OS_GENUNIX
	_OU_TARGET_OS_WINDOWS, // _OU_TARGET_OS_WINDOWS
	_OU_TARGET_OS_QNX, // _OU_TARGET_OS_QNX
	_OU_TARGET_OS_MAC, // _OU_TARGET_OS_MAC
	_OU_TARGET_OS_AIX, // _OU_TARGET_OS_AIX
	_OU_TARGET_OS_SUNOS, // _OU_TARGET_OS_SUNOS
	_OU_TARGET_OS_IOS, // _OU_TARGET_OS_IOS
};
static const CEnumSortedElementArray<int, _OU_TARGET_OS__MAX - 1, int, 100> g_ai_TargetOrderCheck;

template<>
const char *const CEnumUnsortedElementArray<int, _OU_TARGET_OS__MAX - 1, const char *, 100>::m_aetElementArray[] =
{
	"GENERIC UNIX", // _OU_TARGET_OS_GENUNIX
	"WINDOWS", // _OU_TARGET_OS_WINDOWS
	"QNX", // _OU_TARGET_OS_QNX
	"MAC", // _OU_TARGET_OS_MAC
	"AIX", // _OU_TARGET_OS_AIX
	"SunOS", // _OU_TARGET_OS_SUNOS
	"iOS", // _OU_TARGET_OS_IOS
};
static const CEnumUnsortedElementArray<int, _OU_TARGET_OS__MAX - 1, const char *, 100> g_aszOSNames;

// Verifies that bits order is not changed
template<>
int const CEnumSortedElementArray<int, _OU_TARGET_BITS__MAX - 1, int, 101>::m_aetElementArray[] =
{
	_OU_TARGET_BITS_32, // _OU_TARGET_BITS_32
	_OU_TARGET_BITS_64, // _OU_TARGET_BITS_64
};
static const CEnumSortedElementArray<int, _OU_TARGET_BITS__MAX - 1, int, 101> g_ai_BitsOrderCheck;

template<>
const char *const CEnumUnsortedElementArray<int, _OU_TARGET_BITS__MAX - 1, const char *, 101>::m_aetElementArray[] =
{
	"32", // _OU_TARGET_BITS_32
	"64", // _OU_TARGET_BITS_64
};
static const CEnumUnsortedElementArray<int, _OU_TARGET_BITS__MAX - 1, const char *, 101> g_aszBitsNames;

// Verifies that architectures order is not changed
template<>
int const CEnumSortedElementArray<int, _OU_TARGET_ARCH__MAX - 1, int, 102>::m_aetElementArray[] =
{
	_OU_TARGET_ARCH_OTHER, // _OU_TARGET_ARCH_OTHER
	_OU_TARGET_ARCH_X86, // _OU_TARGET_ARCH_X86
	_OU_TARGET_ARCH_IA64, // _OU_TARGET_ARCH_IA64
	_OU_TARGET_ARCH_X64, // _OU_TARGET_ARCH_X64
	_OU_TARGET_ARCH_POWERPC, // _OU_TARGET_ARCH_POWERPC
	_OU_TARGET_ARCH_SPARC, // _OU_TARGET_ARCH_SPARC
	_OU_TARGET_ARCH_ARM, // _OU_TARGET_ARCH_ARM
};
static const CEnumSortedElementArray<int, _OU_TARGET_ARCH__MAX - 1, int, 102> g_ai_ArchitecturesOrderCheck;

template<>
const char *const CEnumUnsortedElementArray<int, _OU_TARGET_ARCH__MAX - 1, const char *, 102>::m_aetElementArray[] =
{
	"OTHER", // _OU_TARGET_ARCH_OTHER
	"x86", // _OU_TARGET_ARCH_X86
	"Itanium", // _OU_TARGET_ARCH_IA64
	"x64", // _OU_TARGET_ARCH_X64
	"PowerPC", // _OU_TARGET_ARCH_POWERPC
	"Sparc", // _OU_TARGET_ARCH_SPARC
	"ARM", // _OU_TARGET_ARCH_ARM
};
static const CEnumUnsortedElementArray<int, _OU_TARGET_ARCH__MAX - 1, const char *, 102> g_aszArchitecturesNames;

// Verifies that compilers order is not changed
template<>
int const CEnumSortedElementArray<int, _OU_COMPILER__MAX - 1, int, 103>::m_aetElementArray[] =
{
	_OU_COMPILER__OTHER, // _OU_COMPILER__OTHER,
	_OU_COMPILER_GCC, // _OU_COMPILER_GCC,
	_OU_COMPILER_MSVC, // _OU_COMPILER_MSVC,
};
static const CEnumSortedElementArray<int, _OU_COMPILER__MAX - 1, int, 103> g_ai_CompilersOrderCheck;

template<>
const char *const CEnumUnsortedElementArray<int, _OU_COMPILER__MAX - 1, const char *, 103>::m_aetElementArray[] =
{
	"UNKNOWN", // _OU_COMPILER__OTHER,
	"GCC", // _OU_COMPILER_GCC,
	"MSVC", // _OU_COMPILER_MSVC,
};
static const CEnumUnsortedElementArray<int, _OU_COMPILER__MAX - 1, const char *, 103> g_aszCompilersNames;

// Verifies that compiler versions order is not changed
template<>
int const CEnumSortedElementArray<int, _OU_COMPILER_VERSION__MAX - 1, int, 104>::m_aetElementArray[] =
{
	_OU_COMPILER_VERSION__OTHER, // _OU_COMPILER_VERSION__OTHER,
	_OU_COMPILER_VERSION_MSVC1998, // _OU_COMPILER_VERSION_MSVC1998,
	_OU_COMPILER_VERSION_GCCLT4, // _OU_COMPILER_VERSION_GCCLT4,
};
static const CEnumSortedElementArray<int, _OU_COMPILER_VERSION__MAX - 1, int, 104> g_ai_CompilersVersionOrderCheck;

template<>
const char *const CEnumUnsortedElementArray<int, _OU_COMPILER_VERSION__MAX - 1, const char *, 104>::m_aetElementArray[] =
{
	"OTHER", // _OU_COMPILER_VERSION__OTHER,
	"MSVC1998", // _OU_COMPILER_VERSION_MSVC1998,
	"GCC LESS THAN 4.0", // _OU_COMPILER_VERSION_GCCLT4,
};
static const CEnumUnsortedElementArray<int, _OU_COMPILER_VERSION__MAX - 1, const char *, 104> g_aszCompilerVersionNames;


#define _TESTPLATFORM_DEFINITION_TEXT(Definition) #Definition
#define TESTPLATFORM_TEFINITION_TEXT(Definition) _TESTPLATFORM_DEFINITION_TEXT(Definition)

bool TestPlatform(unsigned int &nOutSuccessCount, unsigned int &nOutTestCount)
{
	const char *szOSName = g_aszOSNames.Encode(_OU_TARGET_OS - 1);
	const char *szBitsName = g_aszBitsNames.Encode(_OU_TARGET_BITS - 1);
	const char *szArchitectureName = g_aszArchitecturesNames.Encode(_OU_TARGET_ARCH - 1);
	const char *szCompilerName = g_aszCompilersNames.Encode(_OU_COMPILER - 1);
	const char *szCompilerVersion = g_aszCompilerVersionNames.Encode(_OU_COMPILER_VERSION - 1);
	
	printf("Target OS:                   %s\n", szOSName);
	printf("Target Bits:                 %s\n", szBitsName);
	printf("Target Architecture          %s\n", szArchitectureName);
	printf("Compiler Name:               %s\n", szCompilerName);
	printf("Compiler Version:            %s\n", szCompilerVersion);
	printf("Method Convention:           %s\n", TESTPLATFORM_TEFINITION_TEXT(=_OU_CONVENTION_METHOD));
	printf("Function Convention:         %s\n", TESTPLATFORM_TEFINITION_TEXT(=_OU_CONVENTION_API));
	printf("Callback Convention:         %s\n", TESTPLATFORM_TEFINITION_TEXT(=_OU_CONVENTION_CALLBACK));
	printf("Alwaysinline definition:     %s\n", TESTPLATFORM_TEFINITION_TEXT(=_OU_ALWAYSINLINE));
	printf("Inline definition:           %s\n", TESTPLATFORM_TEFINITION_TEXT(=_OU_INLINE));
	
	nOutSuccessCount = 0;
	nOutTestCount = 0;
	return true;
}


//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////

enum EOUSUBSYSTEMTEST
{
	OST__MIN,

	OST_INTTYPES = OST__MIN,
	OST_MACROS,
	OST_TEMPLATES,
	OST_TYPEWRAPPER,
	OST_ASSERT,
	OST_MALLOC,
	OST_CUSTOMIZATION,
	OST_ENUMARRAYS,
	OST_ATOMIC,
	OST_FLAGSDEFINES,
	OST_ATOMICFLAGS,
	OST_SIMPLEFLAGS64,
	OST_SIMPLEFLAGS32,
	OST_SIMPLEFLAGS16,
	OST_SIMPLEFLAGS8,
	OST_TLS,
	OST_PLATFORM,

	OST__MAX,
};

typedef bool (*COUSubsystemTestProcedure)(unsigned int &nOutSuccessCount, unsigned int &nOutTestCount);

template<>
COUSubsystemTestProcedure const CEnumUnsortedElementArray<EOUSUBSYSTEMTEST, OST__MAX, COUSubsystemTestProcedure>::m_aetElementArray[] =
{
	&TestIntTypes, // OST_INTTYPES,
	&TestMacros, // OST_MACROS,
	&TestTemplates, // OST_TEMPLATES,
	&TestTypeWrapper, // OST_TYPEWRAPPER,
	&TestAssert, // OST_ASSERT,
	&TestMalloc, // OST_MALLOC,
	&TestCustomization, // OST_CUSTOMIZATION,
	&TestEnumArrays, // OST_ENUMARRAYS,
	&TestAtomic, // OST_ATOMIC,
	&TestFlagsDefines, // OST_FLAGSDEFINES,
	&TestAtomicFlags, // OST_ATOMICFLAGS,
	&TestSimpleFlags64, // OST_SIMPLEFLAGS64,
	&TestSimpleFlags32, // OST_SIMPLEFLAGS32,
	&TestSimpleFlags16, // OST_SIMPLEFLAGS16,
	&TestSimpleFlags8, // OST_SIMPLEFLAGS8,
	&TestTLS, // OST_TLS,
	&TestPlatform, // OST_PLATFORM,
};
static const CEnumUnsortedElementArray<EOUSUBSYSTEMTEST, OST__MAX, COUSubsystemTestProcedure> g_afnOUSubsystemTestProcedures;

template<>
const char *const CEnumUnsortedElementArray<EOUSUBSYSTEMTEST, OST__MAX, const char *>::m_aetElementArray[] =
{
	"IntTypes", // OST_INTTYPES,
	"Macros", // OST_MACROS,
	"Templates", // OST_TEMPLATES,
	"TypeWrapper", // OST_TYPEWRAPPER,
	"Assert", // OST_ASSERT,
	"Malloc", // OST_MALLOC,
	"Customization", // OST_CUSTOMIZATION,
	"EnumArrays", // OST_ENUMARRAYS,
	"Atomic", // OST_ATOMIC,
	"FlagsDefines", // OST_FLAGSDEFINES,
	"AtomicFlags", // OST_ATOMICFLAGS,
	"SimpleFlags64", // OST_SIMPLEFLAGS64,
	"SimpleFlags32", // OST_SIMPLEFLAGS32,
	"SimpleFlags16", // OST_SIMPLEFLAGS16,
	"SimpleFlags8", // OST_SIMPLEFLAGS8,
	"TLS", // OST_TLS,
	"Platform", // OST_PLATFORM,
};
static const CEnumUnsortedElementArray<EOUSUBSYSTEMTEST, OST__MAX, const char *> g_aszOUSubsystemNames;


bool ProcessOUCoverageTests(unsigned int &nOutFailureCount)
{
	unsigned int nSuccessCount = 0;

	for (EOUSUBSYSTEMTEST stSubsystemTest = OST__MIN; stSubsystemTest != OST__MAX; ++stSubsystemTest)
	{
		const char *szSubsystemName = g_aszOUSubsystemNames.Encode(stSubsystemTest);
		printf("\nTesting subsystem \"%s\"\n", szSubsystemName);
		printf("---------------------------------------------------\n");

		unsigned int nSubsysytemSuccessCount = 0, nSubsystemTestCount = 1;

		COUSubsystemTestProcedure fnTestProcedure = g_afnOUSubsystemTestProcedures.Encode(stSubsystemTest);
		if (fnTestProcedure(nSubsysytemSuccessCount, nSubsystemTestCount) && nSubsysytemSuccessCount == nSubsystemTestCount)
		{
			nSuccessCount += 1;
		}

		unsigned int nSubsysytemFailureCount = nSubsystemTestCount - nSubsysytemSuccessCount;
		printf("---------------------------------------------------\n");
		printf("Feature tests failed:                %3u out of %3u\n", nSubsysytemFailureCount, nSubsystemTestCount);
	}

	unsigned int nFailureCount = OST__MAX - nSuccessCount;
	
	printf("\n===================================================\n");
	printf("Subsystem tests failed:              %3u out of %3u\n", nFailureCount, (unsigned int)OST__MAX);

	nOutFailureCount = nFailureCount;
	return nSuccessCount == OST__MAX;
}

int main(int argc, char* argv[])
{
	unsigned int nFailureCount;
	ProcessOUCoverageTests(nFailureCount);

	return nFailureCount;
}

