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