12e846c40SSergey Makeev // The MIT License (MIT)
22e846c40SSergey Makeev //
32e846c40SSergey Makeev // 	Copyright (c) 2015 Sergey Makeev, Vadim Slyusarev
42e846c40SSergey Makeev //
52e846c40SSergey Makeev // 	Permission is hereby granted, free of charge, to any person obtaining a copy
62e846c40SSergey Makeev // 	of this software and associated documentation files (the "Software"), to deal
72e846c40SSergey Makeev // 	in the Software without restriction, including without limitation the rights
82e846c40SSergey Makeev // 	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
92e846c40SSergey Makeev // 	copies of the Software, and to permit persons to whom the Software is
102e846c40SSergey Makeev // 	furnished to do so, subject to the following conditions:
112e846c40SSergey Makeev //
122e846c40SSergey Makeev //  The above copyright notice and this permission notice shall be included in
132e846c40SSergey Makeev // 	all copies or substantial portions of the Software.
142e846c40SSergey Makeev //
152e846c40SSergey Makeev // 	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
162e846c40SSergey Makeev // 	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
172e846c40SSergey Makeev // 	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
182e846c40SSergey Makeev // 	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
192e846c40SSergey Makeev // 	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
202e846c40SSergey Makeev // 	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
212e846c40SSergey Makeev // 	THE SOFTWARE.
222e846c40SSergey Makeev 
232e846c40SSergey Makeev #pragma once
242e846c40SSergey Makeev 
252e846c40SSergey Makeev #ifndef __MT_STACK__
262e846c40SSergey Makeev #define __MT_STACK__
272e846c40SSergey Makeev 
281e78cb24Ss.makeev_local #include <MTConfig.h>
292e846c40SSergey Makeev #include <array>
302e846c40SSergey Makeev #include <limits>
312e846c40SSergey Makeev 
322e846c40SSergey Makeev namespace MT
332e846c40SSergey Makeev {
342e846c40SSergey Makeev 	static const int32 invalidStackId = 0;
352e846c40SSergey Makeev 	static const int32 invalidStorageId = 0;
362e846c40SSergey Makeev 
372e846c40SSergey Makeev 
382e846c40SSergey Makeev 	//
392e846c40SSergey Makeev 	// Scope descriptor
402e846c40SSergey Makeev 	//
412e846c40SSergey Makeev 	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
422e846c40SSergey Makeev 	class ScopeDesc
432e846c40SSergey Makeev 	{
442e846c40SSergey Makeev 	protected:
452e846c40SSergey Makeev 
462e846c40SSergey Makeev 		//descriptor name
472e846c40SSergey Makeev 		const char* name;
482e846c40SSergey Makeev 
492e846c40SSergey Makeev 		//descriptor declaration file/line
502e846c40SSergey Makeev 		const char* file;
512e846c40SSergey Makeev 		int32 line;
522e846c40SSergey Makeev 
532e846c40SSergey Makeev 	public:
542e846c40SSergey Makeev 
ScopeDesc(const char * srcFile,int32 srcLine,const char * scopeName)552e846c40SSergey Makeev 		ScopeDesc(const char* srcFile, int32 srcLine, const char* scopeName)
56e21e47b6SSergey Makeev 			: name(scopeName)
57e21e47b6SSergey Makeev 			, file(srcFile)
582e846c40SSergey Makeev 			, line(srcLine)
592e846c40SSergey Makeev 		{
602e846c40SSergey Makeev 		}
612e846c40SSergey Makeev 
GetSourceFile()622e846c40SSergey Makeev 		const char* GetSourceFile() const
632e846c40SSergey Makeev 		{
642e846c40SSergey Makeev 			return file;
652e846c40SSergey Makeev 		}
662e846c40SSergey Makeev 
GetSourceLine()672e846c40SSergey Makeev 		int32 GetSourceLine() const
682e846c40SSergey Makeev 		{
692e846c40SSergey Makeev 			return line;
702e846c40SSergey Makeev 		}
712e846c40SSergey Makeev 
GetName()722e846c40SSergey Makeev 		const char* GetName() const
732e846c40SSergey Makeev 		{
742e846c40SSergey Makeev 			return name;
752e846c40SSergey Makeev 		}
762e846c40SSergey Makeev 
772e846c40SSergey Makeev 
782e846c40SSergey Makeev 	};
792e846c40SSergey Makeev 
802e846c40SSergey Makeev 
812e846c40SSergey Makeev 	//
822e846c40SSergey Makeev 	// Scope stack entry
832e846c40SSergey Makeev 	//
842e846c40SSergey Makeev 	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
852e846c40SSergey Makeev 	class ScopeStackEntry
862e846c40SSergey Makeev 	{
872e846c40SSergey Makeev 		int32 parentIndex;
882e846c40SSergey Makeev 		int32 descIndex;
892e846c40SSergey Makeev 
902e846c40SSergey Makeev 	public:
912e846c40SSergey Makeev 
ScopeStackEntry(int32 _parentIndex,int32 _descIndex)922e846c40SSergey Makeev 		ScopeStackEntry(int32 _parentIndex, int32 _descIndex)
932e846c40SSergey Makeev 			: parentIndex(_parentIndex)
942e846c40SSergey Makeev 			, descIndex(_descIndex)
952e846c40SSergey Makeev 		{
962e846c40SSergey Makeev 		}
972e846c40SSergey Makeev 
981e78cb24Ss.makeev_local #if MT_DEBUG
~ScopeStackEntry()992e846c40SSergey Makeev 		~ScopeStackEntry()
1002e846c40SSergey Makeev 		{
1012e846c40SSergey Makeev 			parentIndex = std::numeric_limits<int32>::lowest();
1022e846c40SSergey Makeev 			descIndex = std::numeric_limits<int32>::lowest();
1032e846c40SSergey Makeev 		}
1042e846c40SSergey Makeev #endif
1052e846c40SSergey Makeev 
GetParentId()1062e846c40SSergey Makeev 		int32 GetParentId() const
1072e846c40SSergey Makeev 		{
1082e846c40SSergey Makeev 			return parentIndex;
1092e846c40SSergey Makeev 		}
1102e846c40SSergey Makeev 
GetDescriptionId()1112e846c40SSergey Makeev 		int32 GetDescriptionId() const
1122e846c40SSergey Makeev 		{
1132e846c40SSergey Makeev 			return descIndex;
1142e846c40SSergey Makeev 		}
1152e846c40SSergey Makeev 
1162e846c40SSergey Makeev 
1172e846c40SSergey Makeev 	};
1182e846c40SSergey Makeev 
1192e846c40SSergey Makeev 
1202e846c40SSergey Makeev 	//
1212e846c40SSergey Makeev 	// Persistent scope descriptor storage
1222e846c40SSergey Makeev 	//
1232e846c40SSergey Makeev 	//   persistent storage used to store scope descriptors
1242e846c40SSergey Makeev 	//   descriptors lifetime is equal to the storage lifetime
1252e846c40SSergey Makeev 	//
1262e846c40SSergey Makeev 	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1272e846c40SSergey Makeev 	template<typename T, uint32 capacity>
1282e846c40SSergey Makeev 	class PersistentScopeDescriptorStorage
1292e846c40SSergey Makeev 	{
130c7362320Ss.makeev_local 		static const int32 ALIGNMENT = 16;
131c7362320Ss.makeev_local 		static const int32 ALIGNMENT_MASK = (ALIGNMENT-1);
132c7362320Ss.makeev_local 
133721f8c0bSs.makeev_local 		MT::Atomic32<int32> top;
134c7362320Ss.makeev_local 		//additional bytes for alignment
135c7362320Ss.makeev_local 		byte rawMemory_[ capacity * sizeof(T)  + ALIGNMENT];
136947fea2aSs.makeev_local 
137947fea2aSs.makeev_local 
IndexToObject(int32 index)138c7362320Ss.makeev_local 		T* IndexToObject(int32 index)
139947fea2aSs.makeev_local 		{
140721f8c0bSs.makeev_local 			byte* alignedMemory = (byte*)( ( (uintptr_t)&rawMemory_[0] + ALIGNMENT_MASK ) & ~(uintptr_t)ALIGNMENT_MASK );
141947fea2aSs.makeev_local 			T* pObjectMemory = (T*)(alignedMemory + index * sizeof(T));
142947fea2aSs.makeev_local 			return pObjectMemory;
143947fea2aSs.makeev_local 		}
144947fea2aSs.makeev_local 
1452e846c40SSergey Makeev 
AllocObject(int32 & id)146ab7d8703Ss.makeev 		T* AllocObject(int32 & id)
147ab7d8703Ss.makeev 		{
148ab7d8703Ss.makeev 			//new element index
149ab7d8703Ss.makeev 			int32 index = top.IncFetch() - 1;
15011c09322Ss.makeev 			MT_VERIFY(index < (int32)capacity, "Area allocator is full. Can't allocate more memory.", return nullptr);
151ab7d8703Ss.makeev 			//get memory for object
152c7362320Ss.makeev_local 			T* pObject = IndexToObject(index);
153ab7d8703Ss.makeev 			id = (index + 1);
154ab7d8703Ss.makeev 			return pObject;
155ab7d8703Ss.makeev 		}
156ab7d8703Ss.makeev 
157ab7d8703Ss.makeev 
1582e846c40SSergey Makeev 	public:
1592e846c40SSergey Makeev 
PersistentScopeDescriptorStorage()1602e846c40SSergey Makeev 		PersistentScopeDescriptorStorage()
1612e846c40SSergey Makeev 		{
1622e846c40SSergey Makeev 			static_assert(std::is_base_of<MT::ScopeDesc, T>::value, "Type must be derived from MT::ScopeDesc");
1632e846c40SSergey Makeev 			top.Store(0);
1642e846c40SSergey Makeev 		}
1652e846c40SSergey Makeev 
~PersistentScopeDescriptorStorage()1662e846c40SSergey Makeev 		~PersistentScopeDescriptorStorage()
1672e846c40SSergey Makeev 		{
168721f8c0bSs.makeev_local 			int32 count = top.Exchange(0);
1692e846c40SSergey Makeev 			for (int32 i = 0; i < count; i++)
1702e846c40SSergey Makeev 			{
171c7362320Ss.makeev_local 				T* pObject = IndexToObject(i);
1722e846c40SSergey Makeev 				MT_UNUSED(pObject);
1732e846c40SSergey Makeev 				pObject->~T();
1742e846c40SSergey Makeev 			}
1752e846c40SSergey Makeev 		}
1762e846c40SSergey Makeev 
Alloc(const char * srcFile,int32 srcLine,const char * scopeName)1772e846c40SSergey Makeev 		int32 Alloc(const char* srcFile, int32 srcLine, const char* scopeName)
1782e846c40SSergey Makeev 		{
179ab7d8703Ss.makeev 			int32 id;
180ab7d8703Ss.makeev 			T* pObject = AllocObject(id);
18111c09322Ss.makeev 			if (pObject == nullptr)
18211c09322Ss.makeev 				return invalidStorageId;
1832e846c40SSergey Makeev 
1842e846c40SSergey Makeev 			//placement ctor
1852e846c40SSergey Makeev 			new(pObject) T(srcFile, srcLine, scopeName);
1862e846c40SSergey Makeev 
1872e846c40SSergey Makeev 			return id;
1882e846c40SSergey Makeev 		}
1892e846c40SSergey Makeev 
190ab7d8703Ss.makeev 		template<typename T1>
Alloc(const char * srcFile,int32 srcLine,const char * scopeName,const T1 & p1)191ab7d8703Ss.makeev 		int32 Alloc(const char* srcFile, int32 srcLine, const char* scopeName, const T1 & p1)
192ab7d8703Ss.makeev 		{
193ab7d8703Ss.makeev 			int32 id;
194ab7d8703Ss.makeev 			T* pObject = AllocObject(id);
19511c09322Ss.makeev 			if (pObject == nullptr)
19611c09322Ss.makeev 				return invalidStorageId;
19711c09322Ss.makeev 
198ab7d8703Ss.makeev 			//placement ctor
199ab7d8703Ss.makeev 			new(pObject) T(srcFile, srcLine, scopeName, p1);
200ab7d8703Ss.makeev 			return id;
201ab7d8703Ss.makeev 		}
202ab7d8703Ss.makeev 
203ab7d8703Ss.makeev 		template<typename T1, typename T2>
Alloc(const char * srcFile,int32 srcLine,const char * scopeName,const T1 & p1,const T1 & p2)204ab7d8703Ss.makeev 		int32 Alloc(const char* srcFile, int32 srcLine, const char* scopeName, const T1 & p1, const T1 & p2)
205ab7d8703Ss.makeev 		{
206ab7d8703Ss.makeev 			int32 id;
207ab7d8703Ss.makeev 			T* pObject = AllocObject(id);
20811c09322Ss.makeev 			if (pObject == nullptr)
20911c09322Ss.makeev 				return invalidStorageId;
21011c09322Ss.makeev 
211ab7d8703Ss.makeev 			//placement ctor
212ab7d8703Ss.makeev 			new(pObject) T(srcFile, srcLine, scopeName, p1, p2);
213ab7d8703Ss.makeev 			return id;
214ab7d8703Ss.makeev 		}
215ab7d8703Ss.makeev 
216ab7d8703Ss.makeev 		template<typename T1, typename T2>
Alloc(const char * srcFile,int32 srcLine,const char * scopeName,const T1 & p1,const T1 & p2,const T1 & p3)217ab7d8703Ss.makeev 		int32 Alloc(const char* srcFile, int32 srcLine, const char* scopeName, const T1 & p1, const T1 & p2, const T1 & p3)
218ab7d8703Ss.makeev 		{
219ab7d8703Ss.makeev 			int32 id;
220ab7d8703Ss.makeev 			T* pObject = AllocObject(id);
22111c09322Ss.makeev 			if (pObject == nullptr)
22211c09322Ss.makeev 				return invalidStorageId;
22311c09322Ss.makeev 
224ab7d8703Ss.makeev 			//placement ctor
225ab7d8703Ss.makeev 			new(pObject) T(srcFile, srcLine, scopeName, p1, p2, p3);
226ab7d8703Ss.makeev 			return id;
227ab7d8703Ss.makeev 		}
228ab7d8703Ss.makeev 
Get(int32 id)2292e846c40SSergey Makeev 		T* Get(int32 id)
2302e846c40SSergey Makeev 		{
2312e846c40SSergey Makeev 			MT_VERIFY(id > invalidStorageId, "Invalid ID", return nullptr );
2322e846c40SSergey Makeev 			MT_VERIFY(id <= top.Load(), "Invalid ID", return nullptr );
2332e846c40SSergey Makeev 			int32 index = ( id - 1);
234c7362320Ss.makeev_local 			T* pObject = IndexToObject(index);
2352e846c40SSergey Makeev 			return pObject;
2362e846c40SSergey Makeev 		}
2372e846c40SSergey Makeev 
2382e846c40SSergey Makeev 	};
2392e846c40SSergey Makeev 
2402e846c40SSergey Makeev 
2412e846c40SSergey Makeev 	//
2422e846c40SSergey Makeev 	// Weak scope stack
2432e846c40SSergey Makeev 	//
2442e846c40SSergey Makeev 	//  Weak stack, which means that any data from the stack become invalid after stack entry is popped from stack
2452e846c40SSergey Makeev 	//  Weak stack uses a small amount of memory, but in the case of deferred use the stack entires you must copy this entries to extend lifetime.
2462e846c40SSergey Makeev 	//
2472e846c40SSergey Makeev 	//  Well suited as asset/resource names stack.
2482e846c40SSergey Makeev 	//
2492e846c40SSergey Makeev 	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2502e846c40SSergey Makeev 	template<typename T, uint32 capacity>
2512e846c40SSergey Makeev 	class WeakScopeStack
2522e846c40SSergey Makeev 	{
253c7362320Ss.makeev_local 		static const int32 ALIGNMENT = 16;
254c7362320Ss.makeev_local 		static const int32 ALIGNMENT_MASK = (ALIGNMENT-1);
255c7362320Ss.makeev_local 
256c7362320Ss.makeev_local 		int32 top;
257c7362320Ss.makeev_local 		byte rawMemory_[ capacity * sizeof(T)  + ALIGNMENT];
2582e846c40SSergey Makeev 
IndexToObject(int32 index)2592e846c40SSergey Makeev 		T* IndexToObject(int32 index)
2602e846c40SSergey Makeev 		{
261721f8c0bSs.makeev_local 			byte* alignedMemory = (byte*)( ( (uintptr_t)&rawMemory_[0] + ALIGNMENT_MASK ) & ~(uintptr_t)ALIGNMENT_MASK );
262c7362320Ss.makeev_local 			T* pObjectMemory = (T*)(alignedMemory + index * sizeof(T));
263c7362320Ss.makeev_local 			return pObjectMemory;
2642e846c40SSergey Makeev 		}
2652e846c40SSergey Makeev 
2662e846c40SSergey Makeev 
AllocObject()2672e846c40SSergey Makeev 		T* AllocObject()
2682e846c40SSergey Makeev 		{
2692e846c40SSergey Makeev 			int32 index = top;
270e21e47b6SSergey Makeev 			MT_VERIFY(index < (int32)capacity, "Stack allocator overflow. Can't allocate more memory.", return nullptr);
2712e846c40SSergey Makeev 			top++;
2722e846c40SSergey Makeev 			T* pObject = IndexToObject(index);
2732e846c40SSergey Makeev 			return pObject;
2742e846c40SSergey Makeev 		}
2752e846c40SSergey Makeev 
2762e846c40SSergey Makeev 	public:
2772e846c40SSergey Makeev 
WeakScopeStack()2782e846c40SSergey Makeev 		WeakScopeStack()
2792e846c40SSergey Makeev 		{
2802e846c40SSergey Makeev 			static_assert(std::is_base_of<MT::ScopeStackEntry, T>::value, "Type must be derived from MT::ScopeStackEntry");
2812e846c40SSergey Makeev 			top = invalidStackId;
2822e846c40SSergey Makeev 		}
2832e846c40SSergey Makeev 
~WeakScopeStack()2842e846c40SSergey Makeev 		~WeakScopeStack()
2852e846c40SSergey Makeev 		{
2862e846c40SSergey Makeev 			for(int32 i = 0; i < top; i++)
2872e846c40SSergey Makeev 			{
2882e846c40SSergey Makeev 				T* pObject = IndexToObject(i);
2892e846c40SSergey Makeev 				MT_UNUSED(pObject);
2902e846c40SSergey Makeev 				pObject->~T();
2912e846c40SSergey Makeev 			}
2922e846c40SSergey Makeev 			top = 0;
2932e846c40SSergey Makeev 		}
2942e846c40SSergey Makeev 
2952e846c40SSergey Makeev 
Get(int32 id)2962e846c40SSergey Makeev 		T* Get(int32 id)
2972e846c40SSergey Makeev 		{
2982e846c40SSergey Makeev 			MT_VERIFY(id > invalidStackId, "Invalid id", return nullptr);
2992e846c40SSergey Makeev 			int32 index = (id - 1);
3002e846c40SSergey Makeev 			return IndexToObject(index);
3012e846c40SSergey Makeev 		}
3022e846c40SSergey Makeev 
Top()3032e846c40SSergey Makeev 		int32 Top()
3042e846c40SSergey Makeev 		{
3052e846c40SSergey Makeev 			int32 id = top;
3062e846c40SSergey Makeev 			return id;
3072e846c40SSergey Makeev 		}
3082e846c40SSergey Makeev 
Pop()3092e846c40SSergey Makeev 		void Pop()
3102e846c40SSergey Makeev 		{
3112e846c40SSergey Makeev 			top--;
3122e846c40SSergey Makeev 			int32 index = top;
3132e846c40SSergey Makeev 			MT_ASSERT(index >= 0, "Stack already empty. Invalid call.");
3142e846c40SSergey Makeev 			T* pObject = IndexToObject(index);
3152e846c40SSergey Makeev 			MT_UNUSED(pObject);
3162e846c40SSergey Makeev 			pObject->~T();
3172e846c40SSergey Makeev 		}
3182e846c40SSergey Makeev 
Push()3192e846c40SSergey Makeev 		T* Push()
3202e846c40SSergey Makeev 		{
3212e846c40SSergey Makeev 			T* pObject = AllocObject();
3222e846c40SSergey Makeev 			new(pObject) T();
3232e846c40SSergey Makeev 			return pObject;
3242e846c40SSergey Makeev 		}
3252e846c40SSergey Makeev 
3262e846c40SSergey Makeev 		template<typename T1>
Push(const T1 & p1)327ab7d8703Ss.makeev 		T* Push(const T1 & p1)
3282e846c40SSergey Makeev 		{
3292e846c40SSergey Makeev 			T* pObject = AllocObject();
3302e846c40SSergey Makeev 			new(pObject) T(p1);
3312e846c40SSergey Makeev 			return pObject;
3322e846c40SSergey Makeev 		}
3332e846c40SSergey Makeev 
3342e846c40SSergey Makeev 		template<typename T1, typename T2>
Push(const T1 & p1,const T2 & p2)335ab7d8703Ss.makeev 		T* Push(const T1 & p1, const T2 & p2)
3362e846c40SSergey Makeev 		{
3372e846c40SSergey Makeev 			T* pObject = AllocObject();
3382e846c40SSergey Makeev 			new(pObject) T(p1, p2);
3392e846c40SSergey Makeev 			return pObject;
3402e846c40SSergey Makeev 		}
3412e846c40SSergey Makeev 
3422e846c40SSergey Makeev 		template<typename T1, typename T2, typename T3>
Push(const T1 & p1,const T2 & p2,const T3 & p3)343ab7d8703Ss.makeev 		T* Push(const T1 & p1, const T2 & p2, const T3 & p3)
3442e846c40SSergey Makeev 		{
3452e846c40SSergey Makeev 			T* pObject = AllocObject();
3462e846c40SSergey Makeev 			new(pObject) T(p1, p2, p3);
3472e846c40SSergey Makeev 			return pObject;
3482e846c40SSergey Makeev 		}
3492e846c40SSergey Makeev 
3502e846c40SSergey Makeev 		template<typename T1, typename T2, typename T3, typename T4>
Push(const T1 & p1,const T2 & p2,const T3 & p3,const T4 & p4)351ab7d8703Ss.makeev 		T* Push(const T1 & p1, const T2 & p2, const T3 & p3, const T4 & p4)
3522e846c40SSergey Makeev 		{
3532e846c40SSergey Makeev 			T* pObject = AllocObject();
3542e846c40SSergey Makeev 			new(pObject) T(p1, p2, p3, p4);
3552e846c40SSergey Makeev 			return pObject;
3562e846c40SSergey Makeev 		}
3572e846c40SSergey Makeev 	};
3582e846c40SSergey Makeev 
3592e846c40SSergey Makeev 
3602e846c40SSergey Makeev 	//
3612e846c40SSergey Makeev 	// Strong scope stack
3622e846c40SSergey Makeev 	//
3632e846c40SSergey Makeev 	//  Strong stack, which means that any data from the stack is always valid, until you call Reset();
3642e846c40SSergey Makeev 	//  Strong stack uses a lot of memory, but in the case of deferred use of stack entires you can store single pointer to current stack entry.
3652e846c40SSergey Makeev 	//
3662e846c40SSergey Makeev 	//  Well suited as CPU profiler timings stack.
3672e846c40SSergey Makeev 	//
3682e846c40SSergey Makeev 	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3692e846c40SSergey Makeev 	template<typename T, uint32 capacity>
3702e846c40SSergey Makeev 	class StrongScopeStack
3712e846c40SSergey Makeev 	{
372c7362320Ss.makeev_local 		static const int32 ALIGNMENT = 16;
373c7362320Ss.makeev_local 		static const int32 ALIGNMENT_MASK = (ALIGNMENT-1);
3742e846c40SSergey Makeev 
375c7362320Ss.makeev_local 		int32 count;
376c7362320Ss.makeev_local 		int32 top;
3772e846c40SSergey Makeev 
3782e846c40SSergey Makeev 		//max stack deep
3792e846c40SSergey Makeev 		std::array<int32, 256> stackId;
3802e846c40SSergey Makeev 
381c7362320Ss.makeev_local 		//additional bytes for alignment
382c7362320Ss.makeev_local 		byte rawMemory_[ capacity * sizeof(T) + ALIGNMENT ];
383c7362320Ss.makeev_local 
3842e846c40SSergey Makeev 
IndexToObject(int32 index)3852e846c40SSergey Makeev 		T* IndexToObject(int32 index)
3862e846c40SSergey Makeev 		{
387721f8c0bSs.makeev_local 			byte* alignedMemory = (byte*)( ( (uintptr_t)&rawMemory_[0] + ALIGNMENT_MASK ) & ~(uintptr_t)ALIGNMENT_MASK );
388c7362320Ss.makeev_local 			T* pObjectMemory = (T*)(alignedMemory + index * sizeof(T));
389c7362320Ss.makeev_local 			return pObjectMemory;
3902e846c40SSergey Makeev 		}
3912e846c40SSergey Makeev 
AllocObject()3922e846c40SSergey Makeev 		T* AllocObject()
3932e846c40SSergey Makeev 		{
3942e846c40SSergey Makeev 			int32 stackIndex = top;
3952e846c40SSergey Makeev 			MT_VERIFY(stackIndex < (int32)stackId.size(), "Stack is too deep.", return nullptr);
3962e846c40SSergey Makeev 			top++;
3972e846c40SSergey Makeev 
3982e846c40SSergey Makeev 			int32 index = count;
399e21e47b6SSergey Makeev 			MT_VERIFY(index < (int32)capacity, "Stack allocator overflow. Can't allocate more memory.", return nullptr);
4002e846c40SSergey Makeev 			count++;
4012e846c40SSergey Makeev 			T* pObject = IndexToObject(index);
4022e846c40SSergey Makeev 
4032e846c40SSergey Makeev 			stackId[stackIndex] = (index + 1);
4042e846c40SSergey Makeev 
4052e846c40SSergey Makeev 			return pObject;
4062e846c40SSergey Makeev 		}
4072e846c40SSergey Makeev 
4082e846c40SSergey Makeev 
4092e846c40SSergey Makeev 	public:
4102e846c40SSergey Makeev 
StrongScopeStack()4112e846c40SSergey Makeev 		StrongScopeStack()
4122e846c40SSergey Makeev 		{
4132e846c40SSergey Makeev 			static_assert(std::is_base_of<MT::ScopeStackEntry, T>::value, "Type must be derived from MT::ScopeStackEntry");
4142e846c40SSergey Makeev 			top = invalidStackId;
4152e846c40SSergey Makeev 			count = 0;
4162e846c40SSergey Makeev 		}
4172e846c40SSergey Makeev 
~StrongScopeStack()4182e846c40SSergey Makeev 		~StrongScopeStack()
4192e846c40SSergey Makeev 		{
4202e846c40SSergey Makeev 			Reset();
4212e846c40SSergey Makeev 		}
4222e846c40SSergey Makeev 
Get(int32 id)4232e846c40SSergey Makeev 		T* Get(int32 id)
4242e846c40SSergey Makeev 		{
4252e846c40SSergey Makeev 			MT_VERIFY(id > invalidStackId, "Invalid id", return nullptr);
4262e846c40SSergey Makeev 			int32 index = (id - 1);
4272e846c40SSergey Makeev 			return IndexToObject(index);
4282e846c40SSergey Makeev 		}
4292e846c40SSergey Makeev 
Top()4302e846c40SSergey Makeev 		int32 Top()
4312e846c40SSergey Makeev 		{
4322e846c40SSergey Makeev 			if (top == invalidStackId)
4332e846c40SSergey Makeev 			{
4342e846c40SSergey Makeev 				return invalidStackId;
4352e846c40SSergey Makeev 			}
4362e846c40SSergey Makeev 
4372e846c40SSergey Makeev 			return stackId[top - 1];
4382e846c40SSergey Makeev 		}
4392e846c40SSergey Makeev 
Pop()4402e846c40SSergey Makeev 		void Pop()
4412e846c40SSergey Makeev 		{
4422e846c40SSergey Makeev 			top--;
4432e846c40SSergey Makeev 			int32 index = top;
4442e846c40SSergey Makeev 			MT_ASSERT(index >= 0, "Stack already empty. Invalid call.");
4452e846c40SSergey Makeev 
4462e846c40SSergey Makeev 			stackId[index] = 0;
4472e846c40SSergey Makeev 		}
4482e846c40SSergey Makeev 
4492e846c40SSergey Makeev 
Push()4502e846c40SSergey Makeev 		T* Push()
4512e846c40SSergey Makeev 		{
4522e846c40SSergey Makeev 			T* pObject = AllocObject();
4532e846c40SSergey Makeev 			new(pObject) T();
4542e846c40SSergey Makeev 			return pObject;
4552e846c40SSergey Makeev 		}
4562e846c40SSergey Makeev 
4572e846c40SSergey Makeev 		template<typename T1, typename T2>
Push(T1 p1,T2 p2)4582e846c40SSergey Makeev 		T* Push(T1 p1, T2 p2)
4592e846c40SSergey Makeev 		{
4602e846c40SSergey Makeev 			T* pObject = AllocObject();
4612e846c40SSergey Makeev 			new(pObject) T(p1, p2);
4622e846c40SSergey Makeev 			return pObject;
4632e846c40SSergey Makeev 		}
4642e846c40SSergey Makeev 
4652e846c40SSergey Makeev 		template<typename T1, typename T2, typename T3>
Push(T1 p1,T2 p2,T3 p3)4662e846c40SSergey Makeev 		T* Push(T1 p1, T2 p2, T3 p3)
4672e846c40SSergey Makeev 		{
4682e846c40SSergey Makeev 			T* pObject = AllocObject();
4692e846c40SSergey Makeev 			new(pObject) T(p1, p2, p3);
4702e846c40SSergey Makeev 			return pObject;
4712e846c40SSergey Makeev 		}
4722e846c40SSergey Makeev 
4732e846c40SSergey Makeev 		template<typename T1, typename T2, typename T3, typename T4>
Push(T1 p1,T2 p2,T3 p3,T4 p4)4742e846c40SSergey Makeev 		T* Push(T1 p1, T2 p2, T3 p3, T4 p4)
4752e846c40SSergey Makeev 		{
4762e846c40SSergey Makeev 			T* pObject = AllocObject();
4772e846c40SSergey Makeev 			new(pObject) T(p1, p2, p3, p4);
4782e846c40SSergey Makeev 			return pObject;
4792e846c40SSergey Makeev 		}
4802e846c40SSergey Makeev 
4812e846c40SSergey Makeev 
Reset()4822e846c40SSergey Makeev 		void Reset()
4832e846c40SSergey Makeev 		{
4842e846c40SSergey Makeev 			for(int32 i = 0; i < count; i++)
4852e846c40SSergey Makeev 			{
4862e846c40SSergey Makeev 				T* pObject = IndexToObject(i);
4872e846c40SSergey Makeev 				MT_UNUSED(pObject);
4882e846c40SSergey Makeev 				pObject->~T();
4892e846c40SSergey Makeev 			}
4902e846c40SSergey Makeev 
4911e78cb24Ss.makeev_local #if MT_DEBUG
4922e846c40SSergey Makeev 			int32 stackIdCount = (int32)stackId.size();
4932e846c40SSergey Makeev 			for(int32 i = 0; i < stackIdCount; i++)
4942e846c40SSergey Makeev 			{
4952e846c40SSergey Makeev 				stackId[i] = std::numeric_limits<int32>::lowest();
4962e846c40SSergey Makeev 			}
4972e846c40SSergey Makeev #endif
4982e846c40SSergey Makeev 			count = 0;
4992e846c40SSergey Makeev 			top = invalidStackId;
5002e846c40SSergey Makeev 		}
5012e846c40SSergey Makeev 
5022e846c40SSergey Makeev 	};
5032e846c40SSergey Makeev 
5042e846c40SSergey Makeev } //MT namespace
5052e846c40SSergey Makeev 
50635f63952Ss.makeev 
50735f63952Ss.makeev #define SCOPE_CONCAT_IMPL(x, y) x##y
50835f63952Ss.makeev #define SCOPE_CONCAT(x, y) SCOPE_CONCAT_IMPL(x, y)
50935f63952Ss.makeev 
5109c716f68Ss.makeev_local #define MT_SCOPE_NOT_INITIALIZED (0)
5119c716f68Ss.makeev_local #define MT_SCOPE_NOT_YET_INITIALIZED (-1)
5129c716f68Ss.makeev_local 
513ab7d8703Ss.makeev #define DECLARE_SCOPE_DESCRIPTOR_IMPL_PRE( file, line, name, storagePointer, resultID ) \
5142e846c40SSergey Makeev 	\
5159c716f68Ss.makeev_local 	static MT::Atomic32Base<int32> SCOPE_CONCAT(scope_descriptorIndex_, line) = { MT_SCOPE_NOT_INITIALIZED }; \
516721f8c0bSs.makeev_local 	static_assert(std::is_pod< MT::Atomic32Base<int32> >::value == true, "AtomicInt32Base type should be POD, to be placed in bss/data section"); \
5172e846c40SSergey Makeev 	\
5189c716f68Ss.makeev_local 	int32 SCOPE_CONCAT(scope_descId_, line) = MT_SCOPE_NOT_INITIALIZED; \
5192e846c40SSergey Makeev 	\
5209c716f68Ss.makeev_local 	int32 SCOPE_CONCAT(scope_state_, line) = SCOPE_CONCAT(scope_descriptorIndex_, line).CompareAndSwap(MT_SCOPE_NOT_INITIALIZED, MT_SCOPE_NOT_YET_INITIALIZED); \
52135f63952Ss.makeev 	switch(SCOPE_CONCAT(scope_state_, line)) \
5222e846c40SSergey Makeev 	{ \
5232e846c40SSergey Makeev 		/* first time here, need to allocate descriptor*/ \
5249c716f68Ss.makeev_local 		case MT_SCOPE_NOT_INITIALIZED: \
5252e846c40SSergey Makeev 		{ \
5262e846c40SSergey Makeev 			MT_ASSERT( storagePointer != nullptr, "Scopes storage pointer was not initialized!"); \
527ab7d8703Ss.makeev 
528ab7d8703Ss.makeev 
529ab7d8703Ss.makeev 
530ab7d8703Ss.makeev #define DECLARE_SCOPE_DESCRIPTOR_IMPL_POST( file, line, name, storagePointer, resultID ) \
53135f63952Ss.makeev 			SCOPE_CONCAT(scope_descriptorIndex_, line).Store( SCOPE_CONCAT(scope_descId_, line) );  \
5322e846c40SSergey Makeev 			break; \
5332e846c40SSergey Makeev 		} \
5342e846c40SSergey Makeev 		\
5352e846c40SSergey Makeev 		/* allocation in progress */ \
5362e846c40SSergey Makeev 		/* wait until the allocation is finished */ \
5379c716f68Ss.makeev_local 		case MT_SCOPE_NOT_YET_INITIALIZED: \
5382e846c40SSergey Makeev 		{ \
5392e846c40SSergey Makeev 			for(;;) \
5402e846c40SSergey Makeev 			{ \
54135f63952Ss.makeev 				SCOPE_CONCAT(scope_descId_, line) = SCOPE_CONCAT(scope_descriptorIndex_, line).Load(); \
5429c716f68Ss.makeev_local 				if (SCOPE_CONCAT(scope_descId_, line) != MT_SCOPE_NOT_YET_INITIALIZED) \
5432e846c40SSergey Makeev 				{ \
5442e846c40SSergey Makeev 					break; \
5452e846c40SSergey Makeev 				} \
546*b086e50bSSergey Makeev 				MT::YieldProcessor(); \
5472e846c40SSergey Makeev 			} \
5482e846c40SSergey Makeev 			break; \
5492e846c40SSergey Makeev 		} \
5502e846c40SSergey Makeev 		/* description already allocated */ \
5512e846c40SSergey Makeev 		default: \
5522e846c40SSergey Makeev 		{ \
55335f63952Ss.makeev 			SCOPE_CONCAT(scope_descId_, line) = SCOPE_CONCAT(scope_state_, line); \
5542e846c40SSergey Makeev 			break; \
5552e846c40SSergey Makeev 		} \
5562e846c40SSergey Makeev 	} \
55735f63952Ss.makeev 	resultID = SCOPE_CONCAT(scope_descId_, line);
5582e846c40SSergey Makeev 
5592e846c40SSergey Makeev 
560ab7d8703Ss.makeev 
561ab7d8703Ss.makeev 
562ab7d8703Ss.makeev #define DECLARE_SCOPE_DESCRIPTOR_IMPL( file, line, name, storagePointer, resultID ) \
563ab7d8703Ss.makeev 	DECLARE_SCOPE_DESCRIPTOR_IMPL_PRE(file, line, name, storagePointer, resultID); \
564ab7d8703Ss.makeev 		SCOPE_CONCAT(scope_descId_, line) = storagePointer -> Alloc(file, line, name); \
565ab7d8703Ss.makeev 	DECLARE_SCOPE_DESCRIPTOR_IMPL_POST(file, line, name, storagePointer, resultID); \
566ab7d8703Ss.makeev 
567ab7d8703Ss.makeev 
568ab7d8703Ss.makeev #define DECLARE_SCOPE_DESCRIPTOR_IMPL1( file, line, name, storagePointer, resultID, param1) \
569ab7d8703Ss.makeev 	DECLARE_SCOPE_DESCRIPTOR_IMPL_PRE(file, line, name, storagePointer, resultID); \
570ab7d8703Ss.makeev 		SCOPE_CONCAT(scope_descId_, line) = storagePointer -> Alloc(file, line, name, param1); \
571ab7d8703Ss.makeev 	DECLARE_SCOPE_DESCRIPTOR_IMPL_POST(file, line, name, storagePointer, resultID); \
572ab7d8703Ss.makeev 
573ab7d8703Ss.makeev #define DECLARE_SCOPE_DESCRIPTOR_IMPL2( file, line, name, storagePointer, resultID, param1, param2) \
574ab7d8703Ss.makeev 	DECLARE_SCOPE_DESCRIPTOR_IMPL_PRE(file, line, name, storagePointer, resultID); \
575ab7d8703Ss.makeev 		SCOPE_CONCAT(scope_descId_, line) = storagePointer -> Alloc(file, line, name, param1, param2); \
576ab7d8703Ss.makeev 	DECLARE_SCOPE_DESCRIPTOR_IMPL_POST(file, line, name, storagePointer, resultID); \
577ab7d8703Ss.makeev 
578ab7d8703Ss.makeev 
579ab7d8703Ss.makeev 
5802e846c40SSergey Makeev // declare scope descriptor for current scope.
58135f63952Ss.makeev #define DECLARE_SCOPE_DESCRIPTOR(name, storagePointer, resultID) DECLARE_SCOPE_DESCRIPTOR_IMPL(__FILE__, __LINE__, name, storagePointer, resultID)
5822e846c40SSergey Makeev 
583ab7d8703Ss.makeev #define DECLARE_SCOPE_DESCRIPTOR1(name, storagePointer, resultID, param1) DECLARE_SCOPE_DESCRIPTOR_IMPL1(__FILE__, __LINE__, name, storagePointer, resultID, param1)
584ab7d8703Ss.makeev 
585ab7d8703Ss.makeev #define DECLARE_SCOPE_DESCRIPTOR2(name, storagePointer, resultID, param1, param2) DECLARE_SCOPE_DESCRIPTOR_IMPL2(__FILE__, __LINE__, name, storagePointer, resultID, param1, param2)
586ab7d8703Ss.makeev 
5872e846c40SSergey Makeev // push new stack entry to stack
5882e846c40SSergey Makeev #define SCOPE_STACK_PUSH(scopeDescriptorId, stackPointer) \
5892e846c40SSergey Makeev 	MT_ASSERT(stackPointer != nullptr, "Stack pointer is not initialized for current thread."); \
5909c716f68Ss.makeev_local 	int32 SCOPE_CONCAT(scope_stackParentId_, __LINE__) = stackPointer -> Top(); \
5919c716f68Ss.makeev_local 	MT_ASSERT(SCOPE_CONCAT(scope_stackParentId_, __LINE__) >= 0, "Invalid parent ID"); \
5929c716f68Ss.makeev_local 	stackPointer -> Push(SCOPE_CONCAT(scope_stackParentId_, __LINE__), scopeDescriptorId); \
5932e846c40SSergey Makeev 
5942e846c40SSergey Makeev 
5952e846c40SSergey Makeev // push new stack entry to stack
5962e846c40SSergey Makeev #define SCOPE_STACK_PUSH1(scopeDescriptorId, param1, stackPointer) \
5972e846c40SSergey Makeev 	MT_ASSERT(stackPointer != nullptr, "Stack pointer is not initialized for current thread."); \
5989c716f68Ss.makeev_local 	int32 SCOPE_CONCAT(scope_stackParentId_, __LINE__) = stackPointer -> Top(); \
5999c716f68Ss.makeev_local 	MT_ASSERT(SCOPE_CONCAT(scope_stackParentId_, __LINE__) >= 0, "Invalid parent ID"); \
6009c716f68Ss.makeev_local 	stackPointer -> Push(SCOPE_CONCAT(scope_stackParentId_, __LINE__), scopeDescriptorId, param1); \
6012e846c40SSergey Makeev 
6022e846c40SSergey Makeev // push new stack entry to stack
6032e846c40SSergey Makeev #define SCOPE_STACK_PUSH2(scopeDescriptorId, param1, param2, stackPointer) \
6042e846c40SSergey Makeev 	MT_ASSERT(stackPointer != nullptr, "Stack pointer is not initialized for current thread."); \
6059c716f68Ss.makeev_local 	int32 SCOPE_CONCAT(scope_stackParentId_, __LINE__) = stackPointer -> Top(); \
6069c716f68Ss.makeev_local 	MT_ASSERT(SCOPE_CONCAT(scope_stackParentId_, __LINE__) >= 0, "Invalid parent ID"); \
6079c716f68Ss.makeev_local 	stackPointer -> Push(SCOPE_CONCAT(scope_stackParentId_, __LINE__), scopeDescriptorId, param1, param2); \
6082e846c40SSergey Makeev 
6092e846c40SSergey Makeev 
6102e846c40SSergey Makeev // pop from the stack
6112e846c40SSergey Makeev #define SCOPE_STACK_POP(stackPointer) \
6122e846c40SSergey Makeev 	MT_ASSERT(stackPointer != nullptr, "Stack pointer is not initialized for current thread."); \
6132e846c40SSergey Makeev 	stackPointer -> Pop(); \
6142e846c40SSergey Makeev 
6152e846c40SSergey Makeev // get top of the stack
6162e846c40SSergey Makeev #define SCOPE_STACK_TOP(stackPointer) \
6172e846c40SSergey Makeev 	stackPointer -> Get( stackPointer -> Top() )
6182e846c40SSergey Makeev 
6192e846c40SSergey Makeev 
6202e846c40SSergey Makeev #define SCOPE_STACK_GET_PARENT(stackEntry, stackPointer) \
6212e846c40SSergey Makeev 	(stackEntry -> GetParentId() == MT::invalidStackId) ? nullptr : stackPointer -> Get( stackEntry -> GetParentId() )
6222e846c40SSergey Makeev 
6232e846c40SSergey Makeev 
6242e846c40SSergey Makeev #endif
625