1*b7f5a220SSergey Makeev // The MIT License (MIT)
2*b7f5a220SSergey Makeev //
3*b7f5a220SSergey Makeev // 	Copyright (c) 2015 Sergey Makeev, Vadim Slyusarev
4*b7f5a220SSergey Makeev //
5*b7f5a220SSergey Makeev // 	Permission is hereby granted, free of charge, to any person obtaining a copy
6*b7f5a220SSergey Makeev // 	of this software and associated documentation files (the "Software"), to deal
7*b7f5a220SSergey Makeev // 	in the Software without restriction, including without limitation the rights
8*b7f5a220SSergey Makeev // 	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9*b7f5a220SSergey Makeev // 	copies of the Software, and to permit persons to whom the Software is
10*b7f5a220SSergey Makeev // 	furnished to do so, subject to the following conditions:
11*b7f5a220SSergey Makeev //
12*b7f5a220SSergey Makeev //  The above copyright notice and this permission notice shall be included in
13*b7f5a220SSergey Makeev // 	all copies or substantial portions of the Software.
14*b7f5a220SSergey Makeev //
15*b7f5a220SSergey Makeev // 	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16*b7f5a220SSergey Makeev // 	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17*b7f5a220SSergey Makeev // 	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18*b7f5a220SSergey Makeev // 	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19*b7f5a220SSergey Makeev // 	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20*b7f5a220SSergey Makeev // 	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21*b7f5a220SSergey Makeev // 	THE SOFTWARE.
22*b7f5a220SSergey Makeev 
23*b7f5a220SSergey Makeev #pragma once
24*b7f5a220SSergey Makeev 
25*b7f5a220SSergey Makeev 
26*b7f5a220SSergey Makeev 
27*b7f5a220SSergey Makeev namespace MT
28*b7f5a220SSergey Makeev {
29*b7f5a220SSergey Makeev 
30*b7f5a220SSergey Makeev 	namespace TaskID
31*b7f5a220SSergey Makeev 	{
32*b7f5a220SSergey Makeev 		//unused_id is any odd number, valid_id should be always only even numbers
33*b7f5a220SSergey Makeev 		static const int UNUSED = 1;
34*b7f5a220SSergey Makeev 	}
35*b7f5a220SSergey Makeev 
36*b7f5a220SSergey Makeev 
37*b7f5a220SSergey Makeev 	//forward declaration
38*b7f5a220SSergey Makeev 	class TaskHandle;
39*b7f5a220SSergey Makeev 
40*b7f5a220SSergey Makeev 
41*b7f5a220SSergey Makeev 	/// \class TaskPoolBase
42*b7f5a220SSergey Makeev 	/// \brief
43*b7f5a220SSergey Makeev 	//////////////////////////////////////////////////////////////////////////
44*b7f5a220SSergey Makeev 	struct PoolElementHeader
45*b7f5a220SSergey Makeev 	{
46*b7f5a220SSergey Makeev 		AtomicInt id;
47*b7f5a220SSergey Makeev 
48*b7f5a220SSergey Makeev 	protected:
49*b7f5a220SSergey Makeev 
50*b7f5a220SSergey Makeev 		virtual void Destroy()
51*b7f5a220SSergey Makeev 		{
52*b7f5a220SSergey Makeev 			id.Set(TaskID::UNUSED);
53*b7f5a220SSergey Makeev 		}
54*b7f5a220SSergey Makeev 
55*b7f5a220SSergey Makeev 	public:
56*b7f5a220SSergey Makeev 
57*b7f5a220SSergey Makeev 		PoolElementHeader(int _id)
58*b7f5a220SSergey Makeev 			: id(_id)
59*b7f5a220SSergey Makeev 		{
60*b7f5a220SSergey Makeev 		}
61*b7f5a220SSergey Makeev 
62*b7f5a220SSergey Makeev 		static bool DestoryByHandle(const MT::TaskHandle & handle);
63*b7f5a220SSergey Makeev 	};
64*b7f5a220SSergey Makeev 
65*b7f5a220SSergey Makeev 
66*b7f5a220SSergey Makeev 	/// \class TaskPoolElement
67*b7f5a220SSergey Makeev 	/// \brief
68*b7f5a220SSergey Makeev 	//////////////////////////////////////////////////////////////////////////
69*b7f5a220SSergey Makeev 	template<typename T>
70*b7f5a220SSergey Makeev 	class PoolElement : public PoolElementHeader
71*b7f5a220SSergey Makeev 	{
72*b7f5a220SSergey Makeev 	protected:
73*b7f5a220SSergey Makeev 
74*b7f5a220SSergey Makeev 		virtual void Destroy()
75*b7f5a220SSergey Makeev 		{
76*b7f5a220SSergey Makeev 			PoolElementHeader::Destroy();
77*b7f5a220SSergey Makeev 			//call dtor
78*b7f5a220SSergey Makeev 			task.~T();
79*b7f5a220SSergey Makeev 		}
80*b7f5a220SSergey Makeev 
81*b7f5a220SSergey Makeev 	public:
82*b7f5a220SSergey Makeev 
83*b7f5a220SSergey Makeev 		T task;
84*b7f5a220SSergey Makeev 
85*b7f5a220SSergey Makeev 		PoolElement(int _id, T && _task)
86*b7f5a220SSergey Makeev 			: PoolElementHeader(_id)
87*b7f5a220SSergey Makeev 			, task( std::move(_task) )
88*b7f5a220SSergey Makeev 		{
89*b7f5a220SSergey Makeev 		}
90*b7f5a220SSergey Makeev 
91*b7f5a220SSergey Makeev 	};
92*b7f5a220SSergey Makeev 
93*b7f5a220SSergey Makeev 
94*b7f5a220SSergey Makeev 	/// \class TaskHandle
95*b7f5a220SSergey Makeev 	/// \brief
96*b7f5a220SSergey Makeev 	//////////////////////////////////////////////////////////////////////////
97*b7f5a220SSergey Makeev 	class TaskHandle
98*b7f5a220SSergey Makeev 	{
99*b7f5a220SSergey Makeev 
100*b7f5a220SSergey Makeev 		int check_id;
101*b7f5a220SSergey Makeev 
102*b7f5a220SSergey Makeev 	protected:
103*b7f5a220SSergey Makeev 
104*b7f5a220SSergey Makeev 		friend struct PoolElementHeader;
105*b7f5a220SSergey Makeev 		PoolElementHeader * task;
106*b7f5a220SSergey Makeev 
107*b7f5a220SSergey Makeev 	public:
108*b7f5a220SSergey Makeev 
109*b7f5a220SSergey Makeev 		//default ctor
110*b7f5a220SSergey Makeev 		TaskHandle()
111*b7f5a220SSergey Makeev 			: check_id(TaskID::UNUSED)
112*b7f5a220SSergey Makeev 			, task(nullptr)
113*b7f5a220SSergey Makeev 		{
114*b7f5a220SSergey Makeev 
115*b7f5a220SSergey Makeev 		}
116*b7f5a220SSergey Makeev 
117*b7f5a220SSergey Makeev 		//ctor
118*b7f5a220SSergey Makeev 		TaskHandle(int _id, PoolElementHeader* _task)
119*b7f5a220SSergey Makeev 			: check_id(_id)
120*b7f5a220SSergey Makeev 			, task(_task)
121*b7f5a220SSergey Makeev 		{
122*b7f5a220SSergey Makeev 		}
123*b7f5a220SSergey Makeev 
124*b7f5a220SSergey Makeev 		//copy ctor
125*b7f5a220SSergey Makeev 		TaskHandle(const TaskHandle & other)
126*b7f5a220SSergey Makeev 			: check_id(other.check_id)
127*b7f5a220SSergey Makeev 			, task(other.task)
128*b7f5a220SSergey Makeev 		{
129*b7f5a220SSergey Makeev 		}
130*b7f5a220SSergey Makeev 
131*b7f5a220SSergey Makeev 		//move ctor
132*b7f5a220SSergey Makeev 		TaskHandle(TaskHandle && other)
133*b7f5a220SSergey Makeev 			: check_id(other.check_id)
134*b7f5a220SSergey Makeev 			, task(other.task)
135*b7f5a220SSergey Makeev 		{
136*b7f5a220SSergey Makeev 			other.check_id = TaskID::UNUSED;
137*b7f5a220SSergey Makeev 			other.task = nullptr;
138*b7f5a220SSergey Makeev 		}
139*b7f5a220SSergey Makeev 
140*b7f5a220SSergey Makeev 		~TaskHandle()
141*b7f5a220SSergey Makeev 		{
142*b7f5a220SSergey Makeev 		}
143*b7f5a220SSergey Makeev 
144*b7f5a220SSergey Makeev 		bool IsValid() const
145*b7f5a220SSergey Makeev 		{
146*b7f5a220SSergey Makeev 			if (task == nullptr)
147*b7f5a220SSergey Makeev 			{
148*b7f5a220SSergey Makeev 				return false;
149*b7f5a220SSergey Makeev 			}
150*b7f5a220SSergey Makeev 
151*b7f5a220SSergey Makeev 			if (check_id != task->id.Get())
152*b7f5a220SSergey Makeev 			{
153*b7f5a220SSergey Makeev 				return false;
154*b7f5a220SSergey Makeev 			}
155*b7f5a220SSergey Makeev 
156*b7f5a220SSergey Makeev 			return true;
157*b7f5a220SSergey Makeev 		}
158*b7f5a220SSergey Makeev 
159*b7f5a220SSergey Makeev 	};
160*b7f5a220SSergey Makeev 
161*b7f5a220SSergey Makeev 
162*b7f5a220SSergey Makeev 
163*b7f5a220SSergey Makeev 
164*b7f5a220SSergey Makeev 	//////////////////////////////////////////////////////////////////////////
165*b7f5a220SSergey Makeev 	inline bool PoolElementHeader::DestoryByHandle(const MT::TaskHandle & handle)
166*b7f5a220SSergey Makeev 	{
167*b7f5a220SSergey Makeev 		if (!handle.IsValid())
168*b7f5a220SSergey Makeev 		{
169*b7f5a220SSergey Makeev 			return false;
170*b7f5a220SSergey Makeev 		}
171*b7f5a220SSergey Makeev 
172*b7f5a220SSergey Makeev 		handle.task->Destroy();
173*b7f5a220SSergey Makeev 		return true;
174*b7f5a220SSergey Makeev 	}
175*b7f5a220SSergey Makeev 
176*b7f5a220SSergey Makeev 
177*b7f5a220SSergey Makeev 
178*b7f5a220SSergey Makeev 
179*b7f5a220SSergey Makeev 
180*b7f5a220SSergey Makeev 	/// \class TaskPool
181*b7f5a220SSergey Makeev 	/// \brief
182*b7f5a220SSergey Makeev 	//////////////////////////////////////////////////////////////////////////
183*b7f5a220SSergey Makeev 	template<typename T, size_t N>
184*b7f5a220SSergey Makeev 	class TaskPool
185*b7f5a220SSergey Makeev 	{
186*b7f5a220SSergey Makeev 		typedef PoolElement<T> PoolItem;
187*b7f5a220SSergey Makeev 
188*b7f5a220SSergey Makeev 		//
189*b7f5a220SSergey Makeev 		static const size_t MASK = (N - 1);
190*b7f5a220SSergey Makeev 
191*b7f5a220SSergey Makeev 		void* data;
192*b7f5a220SSergey Makeev 		AtomicInt idGenerator;
193*b7f5a220SSergey Makeev 		AtomicInt index;
194*b7f5a220SSergey Makeev 
195*b7f5a220SSergey Makeev 		inline PoolItem* Buffer()
196*b7f5a220SSergey Makeev 		{
197*b7f5a220SSergey Makeev 			return (PoolItem*)(data);
198*b7f5a220SSergey Makeev 		}
199*b7f5a220SSergey Makeev 
200*b7f5a220SSergey Makeev 		inline void MoveCtor(PoolItem* element, int id, T && val)
201*b7f5a220SSergey Makeev 		{
202*b7f5a220SSergey Makeev 			new(element) PoolItem(id, std::move(val));
203*b7f5a220SSergey Makeev 		}
204*b7f5a220SSergey Makeev 
205*b7f5a220SSergey Makeev 	private:
206*b7f5a220SSergey Makeev 
207*b7f5a220SSergey Makeev 		TaskPool(const TaskPool &) {}
208*b7f5a220SSergey Makeev 		void operator=(const TaskPool &) {}
209*b7f5a220SSergey Makeev 
210*b7f5a220SSergey Makeev 	public:
211*b7f5a220SSergey Makeev 
212*b7f5a220SSergey Makeev 		TaskPool()
213*b7f5a220SSergey Makeev 			: idGenerator(0)
214*b7f5a220SSergey Makeev 			, index(0)
215*b7f5a220SSergey Makeev 		{
216*b7f5a220SSergey Makeev 			static_assert( MT::StaticIsPow2<N>::result, "Task pool capacity must be power of 2");
217*b7f5a220SSergey Makeev 
218*b7f5a220SSergey Makeev 			size_t bytesCount = sizeof(PoolItem) * N;
219*b7f5a220SSergey Makeev 			data = Memory::Alloc(bytesCount);
220*b7f5a220SSergey Makeev 
221*b7f5a220SSergey Makeev 			for(size_t idx = 0; idx < N; idx++)
222*b7f5a220SSergey Makeev 			{
223*b7f5a220SSergey Makeev 				PoolItem* pElement = Buffer() + idx;
224*b7f5a220SSergey Makeev 				pElement->id.Set(TaskID::UNUSED);
225*b7f5a220SSergey Makeev 			}
226*b7f5a220SSergey Makeev 		}
227*b7f5a220SSergey Makeev 
228*b7f5a220SSergey Makeev 		~TaskPool()
229*b7f5a220SSergey Makeev 		{
230*b7f5a220SSergey Makeev 			if (data != nullptr)
231*b7f5a220SSergey Makeev 			{
232*b7f5a220SSergey Makeev 
233*b7f5a220SSergey Makeev 				for(size_t idx = 0; idx < N; idx++)
234*b7f5a220SSergey Makeev 				{
235*b7f5a220SSergey Makeev 					PoolItem* pElement = Buffer() + idx;
236*b7f5a220SSergey Makeev 
237*b7f5a220SSergey Makeev 					int preValue = pElement->id.Set(TaskID::UNUSED);
238*b7f5a220SSergey Makeev 					if (preValue != TaskID::UNUSED)
239*b7f5a220SSergey Makeev 					{
240*b7f5a220SSergey Makeev 						pElement->task.~T();
241*b7f5a220SSergey Makeev 					}
242*b7f5a220SSergey Makeev 				}
243*b7f5a220SSergey Makeev 
244*b7f5a220SSergey Makeev 				Memory::Free(data);
245*b7f5a220SSergey Makeev 				data = nullptr;
246*b7f5a220SSergey Makeev 			}
247*b7f5a220SSergey Makeev 		}
248*b7f5a220SSergey Makeev 
249*b7f5a220SSergey Makeev 
250*b7f5a220SSergey Makeev 		TaskHandle Alloc(T && task)
251*b7f5a220SSergey Makeev 		{
252*b7f5a220SSergey Makeev 			int idx = index.Inc() - 1;
253*b7f5a220SSergey Makeev 
254*b7f5a220SSergey Makeev 			int clampedIdx = (idx & MASK);
255*b7f5a220SSergey Makeev 
256*b7f5a220SSergey Makeev 			PoolItem* pElement = Buffer() + clampedIdx;
257*b7f5a220SSergey Makeev 
258*b7f5a220SSergey Makeev 			bool isUnused = ((pElement->id.Get() & 1 ) != 0);
259*b7f5a220SSergey Makeev 			if (isUnused == false)
260*b7f5a220SSergey Makeev 			{
261*b7f5a220SSergey Makeev 				//Can't allocate more, next element in circular buffer is already used
262*b7f5a220SSergey Makeev 				return TaskHandle();
263*b7f5a220SSergey Makeev 			}
264*b7f5a220SSergey Makeev 
265*b7f5a220SSergey Makeev 			//generate next even number for id
266*b7f5a220SSergey Makeev 			int id = idGenerator.Add(2);
267*b7f5a220SSergey Makeev 			MoveCtor( pElement, id, std::move(task) );
268*b7f5a220SSergey Makeev 			return TaskHandle(id, pElement);
269*b7f5a220SSergey Makeev 		}
270*b7f5a220SSergey Makeev 
271*b7f5a220SSergey Makeev 	};
272*b7f5a220SSergey Makeev 
273*b7f5a220SSergey Makeev }
274