1*d7cf17b1Ss.makeev_local // The MIT License (MIT) 2*d7cf17b1Ss.makeev_local // 3*d7cf17b1Ss.makeev_local // Copyright (c) 2015 Sergey Makeev, Vadim Slyusarev 4*d7cf17b1Ss.makeev_local // 5*d7cf17b1Ss.makeev_local // Permission is hereby granted, free of charge, to any person obtaining a copy 6*d7cf17b1Ss.makeev_local // of this software and associated documentation files (the "Software"), to deal 7*d7cf17b1Ss.makeev_local // in the Software without restriction, including without limitation the rights 8*d7cf17b1Ss.makeev_local // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9*d7cf17b1Ss.makeev_local // copies of the Software, and to permit persons to whom the Software is 10*d7cf17b1Ss.makeev_local // furnished to do so, subject to the following conditions: 11*d7cf17b1Ss.makeev_local // 12*d7cf17b1Ss.makeev_local // The above copyright notice and this permission notice shall be included in 13*d7cf17b1Ss.makeev_local // all copies or substantial portions of the Software. 14*d7cf17b1Ss.makeev_local // 15*d7cf17b1Ss.makeev_local // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16*d7cf17b1Ss.makeev_local // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17*d7cf17b1Ss.makeev_local // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18*d7cf17b1Ss.makeev_local // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19*d7cf17b1Ss.makeev_local // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20*d7cf17b1Ss.makeev_local // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21*d7cf17b1Ss.makeev_local // THE SOFTWARE. 22*d7cf17b1Ss.makeev_local 23*d7cf17b1Ss.makeev_local #pragma once 24*d7cf17b1Ss.makeev_local 25*d7cf17b1Ss.makeev_local #include <vector> 26*d7cf17b1Ss.makeev_local 27*d7cf17b1Ss.makeev_local #include <MTPlatform.h> 28*d7cf17b1Ss.makeev_local #include <MTTools.h> 29*d7cf17b1Ss.makeev_local #include <MTAppInterop.h> 30*d7cf17b1Ss.makeev_local 31*d7cf17b1Ss.makeev_local 32*d7cf17b1Ss.makeev_local namespace MT 33*d7cf17b1Ss.makeev_local { 34*d7cf17b1Ss.makeev_local /// \class TaskQueue 35*d7cf17b1Ss.makeev_local /// \brief thread safe task queue 36*d7cf17b1Ss.makeev_local /// 37*d7cf17b1Ss.makeev_local template<typename T> 38*d7cf17b1Ss.makeev_local class TaskQueue 39*d7cf17b1Ss.makeev_local { 40*d7cf17b1Ss.makeev_local static const int32 ALIGNMENT = 16; 41*d7cf17b1Ss.makeev_local 42*d7cf17b1Ss.makeev_local public: 43*d7cf17b1Ss.makeev_local static const unsigned int CAPACITY = 4096u; 44*d7cf17b1Ss.makeev_local private: 45*d7cf17b1Ss.makeev_local static const unsigned int MASK = CAPACITY - 1u; 46*d7cf17b1Ss.makeev_local 47*d7cf17b1Ss.makeev_local MT::Mutex mutex; 48*d7cf17b1Ss.makeev_local 49*d7cf17b1Ss.makeev_local void* data; 50*d7cf17b1Ss.makeev_local 51*d7cf17b1Ss.makeev_local size_t begin; 52*d7cf17b1Ss.makeev_local size_t end; 53*d7cf17b1Ss.makeev_local 54*d7cf17b1Ss.makeev_local inline T* Buffer() 55*d7cf17b1Ss.makeev_local { 56*d7cf17b1Ss.makeev_local return (T*)(data); 57*d7cf17b1Ss.makeev_local } 58*d7cf17b1Ss.makeev_local 59*d7cf17b1Ss.makeev_local inline void CopyCtor(T* element, const T & val) 60*d7cf17b1Ss.makeev_local { 61*d7cf17b1Ss.makeev_local new(element) T(val); 62*d7cf17b1Ss.makeev_local } 63*d7cf17b1Ss.makeev_local 64*d7cf17b1Ss.makeev_local inline void MoveCtor(T* element, T && val) 65*d7cf17b1Ss.makeev_local { 66*d7cf17b1Ss.makeev_local new(element) T(std::move(val)); 67*d7cf17b1Ss.makeev_local } 68*d7cf17b1Ss.makeev_local 69*d7cf17b1Ss.makeev_local inline void Dtor(T* element) 70*d7cf17b1Ss.makeev_local { 71*d7cf17b1Ss.makeev_local MT_UNUSED(element); 72*d7cf17b1Ss.makeev_local element->~T(); 73*d7cf17b1Ss.makeev_local } 74*d7cf17b1Ss.makeev_local 75*d7cf17b1Ss.makeev_local inline bool _IsEmpty() const 76*d7cf17b1Ss.makeev_local { 77*d7cf17b1Ss.makeev_local return (begin == end); 78*d7cf17b1Ss.makeev_local } 79*d7cf17b1Ss.makeev_local 80*d7cf17b1Ss.makeev_local inline size_t Size() const 81*d7cf17b1Ss.makeev_local { 82*d7cf17b1Ss.makeev_local if (_IsEmpty()) 83*d7cf17b1Ss.makeev_local { 84*d7cf17b1Ss.makeev_local return 0; 85*d7cf17b1Ss.makeev_local } 86*d7cf17b1Ss.makeev_local 87*d7cf17b1Ss.makeev_local size_t count = ((end & MASK) - (begin & MASK)) & MASK; 88*d7cf17b1Ss.makeev_local return count; 89*d7cf17b1Ss.makeev_local } 90*d7cf17b1Ss.makeev_local 91*d7cf17b1Ss.makeev_local inline void Clear() 92*d7cf17b1Ss.makeev_local { 93*d7cf17b1Ss.makeev_local size_t queueSize = Size(); 94*d7cf17b1Ss.makeev_local for (size_t i = 0; i < queueSize; i++) 95*d7cf17b1Ss.makeev_local { 96*d7cf17b1Ss.makeev_local T* pElement = Buffer() + ((begin + i) & MASK); 97*d7cf17b1Ss.makeev_local Dtor(pElement); 98*d7cf17b1Ss.makeev_local } 99*d7cf17b1Ss.makeev_local 100*d7cf17b1Ss.makeev_local begin = 0; 101*d7cf17b1Ss.makeev_local end = 0; 102*d7cf17b1Ss.makeev_local } 103*d7cf17b1Ss.makeev_local 104*d7cf17b1Ss.makeev_local 105*d7cf17b1Ss.makeev_local public: 106*d7cf17b1Ss.makeev_local 107*d7cf17b1Ss.makeev_local MT_NOCOPYABLE(TaskQueue); 108*d7cf17b1Ss.makeev_local 109*d7cf17b1Ss.makeev_local /// \name Initializes a new instance of the TaskQueue class. 110*d7cf17b1Ss.makeev_local /// \brief 111*d7cf17b1Ss.makeev_local TaskQueue() 112*d7cf17b1Ss.makeev_local : begin(0) 113*d7cf17b1Ss.makeev_local , end(0) 114*d7cf17b1Ss.makeev_local { 115*d7cf17b1Ss.makeev_local size_t bytesCount = sizeof(T) * CAPACITY; 116*d7cf17b1Ss.makeev_local data = Memory::Alloc(bytesCount, ALIGNMENT); 117*d7cf17b1Ss.makeev_local } 118*d7cf17b1Ss.makeev_local 119*d7cf17b1Ss.makeev_local ~TaskQueue() 120*d7cf17b1Ss.makeev_local { 121*d7cf17b1Ss.makeev_local if (data != nullptr) 122*d7cf17b1Ss.makeev_local { 123*d7cf17b1Ss.makeev_local Memory::Free(data); 124*d7cf17b1Ss.makeev_local data = nullptr; 125*d7cf17b1Ss.makeev_local } 126*d7cf17b1Ss.makeev_local } 127*d7cf17b1Ss.makeev_local 128*d7cf17b1Ss.makeev_local /// \brief Add multiple tasks onto queue. 129*d7cf17b1Ss.makeev_local /// \param itemArray A pointer to first item. Must not be nullptr 130*d7cf17b1Ss.makeev_local /// \param count Items count. 131*d7cf17b1Ss.makeev_local bool Add(const T* itemArray, size_t count) 132*d7cf17b1Ss.makeev_local { 133*d7cf17b1Ss.makeev_local MT::ScopedGuard guard(mutex); 134*d7cf17b1Ss.makeev_local 135*d7cf17b1Ss.makeev_local if ((Size() + count) >= CAPACITY) 136*d7cf17b1Ss.makeev_local { 137*d7cf17b1Ss.makeev_local return false; 138*d7cf17b1Ss.makeev_local } 139*d7cf17b1Ss.makeev_local 140*d7cf17b1Ss.makeev_local for (size_t i = 0; i < count; ++i) 141*d7cf17b1Ss.makeev_local { 142*d7cf17b1Ss.makeev_local size_t index = (end & MASK); 143*d7cf17b1Ss.makeev_local T* pElement = Buffer() + index; 144*d7cf17b1Ss.makeev_local CopyCtor( pElement, itemArray[i] ); 145*d7cf17b1Ss.makeev_local end++; 146*d7cf17b1Ss.makeev_local } 147*d7cf17b1Ss.makeev_local 148*d7cf17b1Ss.makeev_local return true; 149*d7cf17b1Ss.makeev_local } 150*d7cf17b1Ss.makeev_local 151*d7cf17b1Ss.makeev_local 152*d7cf17b1Ss.makeev_local /// \brief Try pop oldest item from queue. 153*d7cf17b1Ss.makeev_local /// \param item Resultant item 154*d7cf17b1Ss.makeev_local /// \return true on success or false if the queue is empty. 155*d7cf17b1Ss.makeev_local bool TryPopOldest(T & item) 156*d7cf17b1Ss.makeev_local { 157*d7cf17b1Ss.makeev_local MT::ScopedGuard guard(mutex); 158*d7cf17b1Ss.makeev_local 159*d7cf17b1Ss.makeev_local if (_IsEmpty()) 160*d7cf17b1Ss.makeev_local { 161*d7cf17b1Ss.makeev_local return false; 162*d7cf17b1Ss.makeev_local } 163*d7cf17b1Ss.makeev_local 164*d7cf17b1Ss.makeev_local size_t index = (begin & MASK); 165*d7cf17b1Ss.makeev_local T* pElement = Buffer() + index; 166*d7cf17b1Ss.makeev_local begin++; 167*d7cf17b1Ss.makeev_local item = *pElement; 168*d7cf17b1Ss.makeev_local Dtor(pElement); 169*d7cf17b1Ss.makeev_local return true; 170*d7cf17b1Ss.makeev_local } 171*d7cf17b1Ss.makeev_local 172*d7cf17b1Ss.makeev_local /// \brief Try pop a newest item (recently added) from queue. 173*d7cf17b1Ss.makeev_local /// \param item Resultant item 174*d7cf17b1Ss.makeev_local /// \return true on success or false if the queue is empty. 175*d7cf17b1Ss.makeev_local bool TryPopNewest(T & item) 176*d7cf17b1Ss.makeev_local { 177*d7cf17b1Ss.makeev_local MT::ScopedGuard guard(mutex); 178*d7cf17b1Ss.makeev_local 179*d7cf17b1Ss.makeev_local if (_IsEmpty()) 180*d7cf17b1Ss.makeev_local { 181*d7cf17b1Ss.makeev_local return false; 182*d7cf17b1Ss.makeev_local } 183*d7cf17b1Ss.makeev_local 184*d7cf17b1Ss.makeev_local end--; 185*d7cf17b1Ss.makeev_local size_t index = (end & MASK); 186*d7cf17b1Ss.makeev_local T* pElement = Buffer() + index; 187*d7cf17b1Ss.makeev_local item = *pElement; 188*d7cf17b1Ss.makeev_local Dtor(pElement); 189*d7cf17b1Ss.makeev_local return true; 190*d7cf17b1Ss.makeev_local } 191*d7cf17b1Ss.makeev_local 192*d7cf17b1Ss.makeev_local /// \brief Check if queue is empty. 193*d7cf17b1Ss.makeev_local /// \return true - if queue is empty. 194*d7cf17b1Ss.makeev_local bool IsEmpty() 195*d7cf17b1Ss.makeev_local { 196*d7cf17b1Ss.makeev_local MT::ScopedGuard guard(mutex); 197*d7cf17b1Ss.makeev_local 198*d7cf17b1Ss.makeev_local return _IsEmpty(); 199*d7cf17b1Ss.makeev_local } 200*d7cf17b1Ss.makeev_local 201*d7cf17b1Ss.makeev_local }; 202*d7cf17b1Ss.makeev_local } 203