| 
									
										
										
										
											2014-02-10 13:54:46 -05:00
										 |  |  | #pragma once
 | 
					
						
							| 
									
										
										
										
											2010-07-29 10:21:48 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | // a simple lockless thread-safe,
 | 
					
						
							|  |  |  | // single reader, single writer queue
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-20 04:11:52 +01:00
										 |  |  | #include <algorithm>
 | 
					
						
							|  |  |  | #include <cstddef>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-17 05:18:15 -05:00
										 |  |  | #include "Common/Atomic.h"
 | 
					
						
							| 
									
										
										
										
											2014-02-20 04:11:52 +01:00
										 |  |  | #include "Common/CommonTypes.h"
 | 
					
						
							| 
									
										
										
										
											2010-08-10 04:12:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-29 10:21:48 +00:00
										 |  |  | namespace Common | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-08-19 15:16:01 -04:00
										 |  |  | template <typename T, bool NeedSize = true> | 
					
						
							| 
									
										
										
										
											2010-07-29 10:21:48 +00:00
										 |  |  | class FifoQueue | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | public: | 
					
						
							| 
									
										
										
										
											2010-08-10 04:12:32 +00:00
										 |  |  | 	FifoQueue() : m_size(0) | 
					
						
							| 
									
										
										
										
											2010-07-29 10:21:48 +00:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		 m_write_ptr = m_read_ptr = new ElementPtr(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	~FifoQueue() | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		// this will empty out the whole queue
 | 
					
						
							|  |  |  | 		delete m_read_ptr; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-10 04:12:32 +00:00
										 |  |  | 	u32 Size() const | 
					
						
							| 
									
										
										
										
											2010-07-29 10:21:48 +00:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2013-08-19 15:16:01 -04:00
										 |  |  | 		static_assert(NeedSize, "using Size() on FifoQueue without NeedSize"); | 
					
						
							| 
									
										
										
										
											2010-08-10 04:12:32 +00:00
										 |  |  | 		return m_size; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	bool Empty() const | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2013-08-29 19:19:44 -04:00
										 |  |  | 		return !AtomicLoad(m_read_ptr->next); | 
					
						
							| 
									
										
										
										
											2010-08-10 04:12:32 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-04 19:34:50 -05:00
										 |  |  | 	T& Front() const | 
					
						
							| 
									
										
										
										
											2010-08-10 04:12:32 +00:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2013-08-29 19:19:44 -04:00
										 |  |  | 		AtomicLoadAcquire(m_read_ptr->next); | 
					
						
							| 
									
										
										
										
											2013-08-19 15:16:01 -04:00
										 |  |  | 		return m_read_ptr->current; | 
					
						
							| 
									
										
										
										
											2010-07-29 10:21:48 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-04 19:34:50 -05:00
										 |  |  | 	template <typename Arg> | 
					
						
							|  |  |  | 	void Push(Arg&& t) | 
					
						
							| 
									
										
										
										
											2010-07-29 10:21:48 +00:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		// create the element, add it to the queue
 | 
					
						
							| 
									
										
										
										
											2013-09-22 20:38:03 -04:00
										 |  |  | 		m_write_ptr->current = std::forward<Arg>(t); | 
					
						
							| 
									
										
										
										
											2010-07-29 10:21:48 +00:00
										 |  |  | 		// set the next pointer to a new element ptr
 | 
					
						
							| 
									
										
										
										
											2013-10-29 01:23:17 -04:00
										 |  |  | 		// then advance the write pointer
 | 
					
						
							| 
									
										
										
										
											2013-08-29 19:19:44 -04:00
										 |  |  | 		ElementPtr* new_ptr = new ElementPtr(); | 
					
						
							|  |  |  | 		AtomicStoreRelease(m_write_ptr->next, new_ptr); | 
					
						
							|  |  |  | 		m_write_ptr = new_ptr; | 
					
						
							| 
									
										
										
										
											2013-08-19 15:16:01 -04:00
										 |  |  | 		if (NeedSize) | 
					
						
							|  |  |  | 			Common::AtomicIncrement(m_size); | 
					
						
							| 
									
										
										
										
											2010-07-29 10:21:48 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-10 04:12:32 +00:00
										 |  |  | 	void Pop() | 
					
						
							| 
									
										
										
										
											2010-07-29 10:21:48 +00:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2013-08-19 15:16:01 -04:00
										 |  |  | 		if (NeedSize) | 
					
						
							|  |  |  | 			Common::AtomicDecrement(m_size); | 
					
						
							|  |  |  | 		ElementPtr *tmpptr = m_read_ptr; | 
					
						
							| 
									
										
										
										
											2010-07-29 10:21:48 +00:00
										 |  |  | 		// advance the read pointer
 | 
					
						
							| 
									
										
										
										
											2013-08-29 19:19:44 -04:00
										 |  |  | 		m_read_ptr = AtomicLoad(tmpptr->next); | 
					
						
							| 
									
										
										
										
											2014-03-09 21:14:26 +01:00
										 |  |  | 		// set the next element to nullptr to stop the recursive deletion
 | 
					
						
							|  |  |  | 		tmpptr->next = nullptr; | 
					
						
							| 
									
										
										
										
											2014-02-16 23:51:41 -05:00
										 |  |  | 		delete tmpptr; // this also deletes the element
 | 
					
						
							| 
									
										
										
										
											2010-07-29 10:21:48 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-10 04:12:32 +00:00
										 |  |  | 	bool Pop(T& t) | 
					
						
							| 
									
										
										
										
											2010-07-29 10:21:48 +00:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2010-08-10 04:12:32 +00:00
										 |  |  | 		if (Empty()) | 
					
						
							| 
									
										
										
										
											2010-07-29 10:21:48 +00:00
										 |  |  | 			return false; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-08-29 19:19:44 -04:00
										 |  |  | 		if (NeedSize) | 
					
						
							|  |  |  | 			Common::AtomicDecrement(m_size); | 
					
						
							| 
									
										
										
										
											2010-07-29 10:21:48 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-08-29 19:19:44 -04:00
										 |  |  | 		ElementPtr *tmpptr = m_read_ptr; | 
					
						
							|  |  |  | 		m_read_ptr = AtomicLoadAcquire(tmpptr->next); | 
					
						
							|  |  |  | 		t = std::move(tmpptr->current); | 
					
						
							| 
									
										
										
										
											2014-03-09 21:14:26 +01:00
										 |  |  | 		tmpptr->next = nullptr; | 
					
						
							| 
									
										
										
										
											2013-08-29 19:19:44 -04:00
										 |  |  | 		delete tmpptr; | 
					
						
							| 
									
										
										
										
											2010-07-29 10:21:48 +00:00
										 |  |  | 		return true; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-10 04:12:32 +00:00
										 |  |  | 	// not thread-safe
 | 
					
						
							|  |  |  | 	void Clear() | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		m_size = 0; | 
					
						
							|  |  |  | 		delete m_read_ptr; | 
					
						
							|  |  |  | 		m_write_ptr = m_read_ptr = new ElementPtr(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-29 10:21:48 +00:00
										 |  |  | private: | 
					
						
							| 
									
										
										
										
											2010-08-10 04:12:32 +00:00
										 |  |  | 	// stores a pointer to element
 | 
					
						
							| 
									
										
										
										
											2010-07-29 10:21:48 +00:00
										 |  |  | 	// and a pointer to the next ElementPtr
 | 
					
						
							|  |  |  | 	class ElementPtr | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 	public: | 
					
						
							| 
									
										
										
										
											2014-03-09 21:14:26 +01:00
										 |  |  | 		ElementPtr() : next(nullptr) {} | 
					
						
							| 
									
										
										
										
											2010-07-29 10:21:48 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		~ElementPtr() | 
					
						
							|  |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2013-08-19 15:16:01 -04:00
										 |  |  | 			if (next) | 
					
						
							|  |  |  | 				delete next; | 
					
						
							| 
									
										
										
										
											2010-07-29 10:21:48 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-08-19 15:16:01 -04:00
										 |  |  | 		T current; | 
					
						
							| 
									
										
										
										
											2010-07-29 10:21:48 +00:00
										 |  |  | 		ElementPtr *volatile next; | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-08-19 15:16:01 -04:00
										 |  |  | 	ElementPtr *m_write_ptr; | 
					
						
							|  |  |  | 	ElementPtr *m_read_ptr; | 
					
						
							| 
									
										
										
										
											2010-08-10 04:12:32 +00:00
										 |  |  | 	volatile u32 m_size; | 
					
						
							| 
									
										
										
										
											2010-07-29 10:21:48 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } |