// This is a part of the Microsoft Foundation Classes C++ library.
// Copyright (C) Microsoft Corporation
// All rights reserved.
//
// This source code is only intended as a supplement to the
// Microsoft Foundation Classes Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// Microsoft Foundation Classes product.

#ifndef __AFXTLS_H__
#define __AFXTLS_H__

#pragma once

#ifdef _AFX_PACKING
#pragma pack(push, _AFX_PACKING)
#endif

#ifdef _AFX_MINREBUILD
#pragma component(minrebuild, off)
#endif

#undef AFX_DATA
#define AFX_DATA AFX_CORE_DATA

// Classes declared in this file

class CSimpleList;
class CThreadSlotData;                  // for manipulationg thread local storage
class CThreadLocalObject;               // for storing thread local data
class CProcessLocalObject;              // for storing thread local data
class CNoTrackObject;

// template class CTypedSimpleList<>
// template class CThreadLocal<>
// template class CProcessLocal<>

/////////////////////////////////////////////////////////////////////////////
// CSimpleList (simple/small subset of CList)

class CSimpleList
{
public:
	CSimpleList(int nNextOffset = 0);
	void Construct(int nNextOffset);

// Operations
	BOOL IsEmpty() const;
	void AddHead(void* p);
	void RemoveAll();
	void* GetHead() const;
	void* GetNext(void* p) const;
	BOOL Remove(void* p);

// Implementation
	void* m_pHead;
	size_t m_nNextOffset;

	void** GetNextPtr(void* p) const;   // somewhat trusting...
};

AFX_INLINE CSimpleList::CSimpleList(int nNextOffset)
	{ m_pHead = NULL; m_nNextOffset = nNextOffset; }
AFX_INLINE void CSimpleList::Construct(int nNextOffset)
	{ ASSERT(m_pHead == NULL); m_nNextOffset = nNextOffset; }
AFX_INLINE BOOL CSimpleList::IsEmpty() const
	{ return m_pHead == NULL; }
AFX_INLINE void** CSimpleList::GetNextPtr(void* p) const
	{ ENSURE_ARG(p != NULL); return (void**)((BYTE*)p+m_nNextOffset); }
AFX_INLINE void CSimpleList::RemoveAll()
	{ m_pHead = NULL; }
AFX_INLINE void* CSimpleList::GetHead() const
	{ return m_pHead; }
AFX_INLINE void* CSimpleList::GetNext(void* prevElement) const
	{ return *GetNextPtr(prevElement); }

template<class TYPE>
class CTypedSimpleList : public CSimpleList
{
public:
	CTypedSimpleList(int nNextOffset = 0)
		: CSimpleList(nNextOffset) { }
	void AddHead(TYPE p)
		{ CSimpleList::AddHead(p); }
	TYPE GetHead()
		{ return (TYPE)CSimpleList::GetHead(); }
	TYPE GetNext(TYPE p)
		{ return (TYPE)CSimpleList::GetNext(p); }
	BOOL Remove(TYPE p)
		{ return CSimpleList::Remove((TYPE)p); }
	operator TYPE();		
};
template<class TYPE>
inline CTypedSimpleList<TYPE>::operator TYPE()
{ 
	return (TYPE)CSimpleList::GetHead(); 
}
/////////////////////////////////////////////////////////////////////////////
// CThreadSlotData - manages owned array of "slots" for thread local storage

struct CThreadData; // private to implementation
struct CSlotData;   // private to implementation

class CThreadSlotData
{
public:
	CThreadSlotData();

// Operations
	int AllocSlot();
	void FreeSlot(int nSlot);	
	void SetValue(int nSlot, void* pValue);
	// delete all values in process/thread
	void DeleteValues(HINSTANCE hInst, BOOL bAll = FALSE);
	// assign instance handle to just constructed slots
	void AssignInstance(HINSTANCE hInst);

// Implementation
	DWORD m_tlsIndex;   // used to access system thread-local storage

	int m_nAlloc;       // number of slots allocated (in UINTs)
	int m_nRover;       // (optimization) for quick finding of free slots
	int m_nMax;         // size of slot table below (in bits)
	CSlotData* m_pSlotData; // state of each slot (allocated or not)
	CTypedSimpleList<CThreadData*> m_list;  // list of CThreadData structures
	CRITICAL_SECTION m_sect;

	void* GetThreadValue(int nSlot); // special version for threads only!
	void* PASCAL operator new(size_t, void* p)
		{ return p; }
	void DeleteValues(CThreadData* pData, HINSTANCE hInst);
	~CThreadSlotData();
};

class AFX_NOVTABLE CNoTrackObject
{
public:
	void* PASCAL operator new(size_t nSize);
	void PASCAL operator delete(void*);

#if defined(_DEBUG) && !defined(_AFX_NO_DEBUG_CRT)
	void* PASCAL operator new(size_t nSize, LPCSTR, int);
	void PASCAL operator delete(void* pObject, LPCSTR, int);
#endif
    virtual ~CNoTrackObject() {};
};

class AFX_NOVTABLE CThreadLocalObject
{
public:
// Attributes
	CNoTrackObject* GetData(CNoTrackObject* (AFXAPI* pfnCreateObject)());
	CNoTrackObject* GetDataNA();

// Implementation
	int m_nSlot;
	~CThreadLocalObject();
};

class AFX_NOVTABLE CProcessLocalObject
{
public:
// Attributes
	CNoTrackObject* GetData(CNoTrackObject* (AFXAPI* pfnCreateObject)());

// Implementation
	CNoTrackObject* volatile m_pObject;
	~CProcessLocalObject();
};

template<class TYPE>
class CThreadLocal : public CThreadLocalObject
{
// Attributes
public:
	AFX_INLINE TYPE* GetData()
	{
		TYPE* pData = (TYPE*)CThreadLocalObject::GetData(&CreateObject);
		ENSURE(pData != NULL);
		return pData;
	}
	AFX_INLINE TYPE* GetDataNA()
	{
		TYPE* pData = (TYPE*)CThreadLocalObject::GetDataNA();
		return pData;
	}
	AFX_INLINE operator TYPE*()
	{ 
		return GetData(); 
	}
	AFX_INLINE TYPE* operator->()
	{ 
		return GetData(); 
	}

// Implementation
public:
	static CNoTrackObject* AFXAPI CreateObject()
		{ return new TYPE; }
};

#define THREAD_LOCAL(class_name, ident_name) \
	AFX_COMDAT CThreadLocal<class_name> ident_name;
#define EXTERN_THREAD_LOCAL(class_name, ident_name) \
	extern CThreadLocal<class_name> ident_name;

template<class TYPE>
class CProcessLocal : public CProcessLocalObject
{
// Attributes
public:
	AFX_INLINE TYPE* GetData()
	{
		TYPE* pData = (TYPE*)CProcessLocalObject::GetData(&CreateObject);
		ENSURE(pData != NULL);
		return pData;
	}
	AFX_INLINE TYPE* GetDataNA()
		{ return (TYPE*)m_pObject; }
	AFX_INLINE operator TYPE*()
		{ return GetData(); }
	AFX_INLINE TYPE* operator->()
		{ return GetData(); }

// Implementation
public:
	static CNoTrackObject* AFXAPI CreateObject()
		{ return new TYPE; }
};

#define PROCESS_LOCAL(class_name, ident_name) \
	AFX_COMDAT CProcessLocal<class_name> ident_name;
#define EXTERN_PROCESS_LOCAL(class_name, ident_name) \
	extern CProcessLocal<class_name> ident_name;

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

void AFXAPI AfxInitLocalData(HINSTANCE hInstInit);
void AFXAPI AfxTermLocalData(HINSTANCE hInstTerm, BOOL bAll = FALSE);
void AFXAPI AfxTlsAddRef();
void AFXAPI AfxTlsRelease();

#ifdef _AFX_MINREBUILD
#pragma component(minrebuild, on)
#endif

#ifdef _AFX_PACKING
#pragma pack(pop)
#endif

#undef AFX_DATA
#define AFX_DATA

#endif //__AFXTLS_H__

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