core/sm_queue.h
author Anthony Iacono <anthonyiacono@gmail.com>
Sun Aug 26 23:33:04 2012 -0400 (2012-08-26)
changeset 3632 2fe3c4c0eb76
parent 2471 194be299b700
permissions -rw-r--r--
Fixed OnClientConnect blocking not actually functioning (bug 5461, r=psychonic).
     1 /**
     2  * vim: set ts=4 :
     3  * =============================================================================
     4  * SourceMod
     5  * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
     6  * =============================================================================
     7  *
     8  * This program is free software; you can redistribute it and/or modify it under
     9  * the terms of the GNU General Public License, version 3.0, as published by the
    10  * Free Software Foundation.
    11  * 
    12  * This program is distributed in the hope that it will be useful, but WITHOUT
    13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    14  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    15  * details.
    16  *
    17  * You should have received a copy of the GNU General Public License along with
    18  * this program.  If not, see <http://www.gnu.org/licenses/>.
    19  *
    20  * As a special exception, AlliedModders LLC gives you permission to link the
    21  * code of this program (as well as its derivative works) to "Half-Life 2," the
    22  * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
    23  * by the Valve Corporation.  You must obey the GNU General Public License in
    24  * all respects for all other code used.  Additionally, AlliedModders LLC grants
    25  * this exception to all derivative works.  AlliedModders LLC defines further
    26  * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
    27  * or <http://www.sourcemod.net/license.php>.
    28  *
    29  * Version: $Id$
    30  */
    31 
    32 #ifndef _INCLUDE_SM_QUEUE_H
    33 #define _INCLUDE_SM_QUEUE_H
    34 
    35 #include <new>
    36 #include <stdlib.h>
    37 #include <sh_stack.h>
    38 
    39 using namespace SourceHook;
    40 
    41 /*
    42 	A circular, doubly-linked List with one sentinel node
    43 
    44 	Empty:
    45 	m_Head = sentinel
    46 	m_Head->next = m_Head;
    47 	m_Head->prev = m_Head;
    48 	One element:
    49 	m_Head = sentinel
    50 	m_Head->next = node1
    51 	m_Head->prev = node1
    52 	node1->next = m_Head
    53 	node1->prev = m_Head
    54 	Two elements:
    55 	m_Head = sentinel
    56 	m_Head->next = node1
    57 	m_Head->prev = node2
    58 	node1->next = node2
    59 	node1->prev = m_Head
    60 	node2->next = m_Head
    61 	node2->prev = node1
    62 */
    63 template <class T>
    64 class Queue
    65 {
    66 public:
    67 	class iterator;
    68 	friend class iterator;
    69 	class QueueNode
    70 	{
    71 	public:
    72 		T obj;
    73 		QueueNode *next;
    74 		QueueNode *prev;
    75 	};
    76 private:
    77 	// Initializes the sentinel node.
    78 	QueueNode *_Initialize()
    79 	{
    80 		QueueNode *n = (QueueNode *)malloc(sizeof(QueueNode));
    81 		n->next = n;
    82 		n->prev = n;
    83 		return n;
    84 	}
    85 public:
    86 	Queue() : m_Head(_Initialize()), m_Size(0)
    87 	{
    88 	}
    89 
    90 	Queue(const Queue &src) : m_Head(_Initialize()), m_Size(0)
    91 	{
    92 		iterator iter;
    93 		for (iter=src.begin(); iter!=src.end(); iter++)
    94 		{
    95 			push_back( (*iter) );
    96 		}
    97 	}
    98 
    99 	~Queue()
   100 	{
   101 		clear();
   102 
   103 		// Don't forget to free the sentinel
   104 		if (m_Head)
   105 		{
   106 			free(m_Head);
   107 			m_Head = NULL;
   108 		}
   109 
   110 		while (!m_FreeNodes.empty())
   111 		{
   112 			free(m_FreeNodes.front());
   113 			m_FreeNodes.pop();
   114 		}
   115 	}
   116 
   117 	void push(const T &obj)
   118 	{
   119 		QueueNode *node;
   120 		
   121 		if (m_FreeNodes.empty())
   122 		{
   123 			node = (QueueNode *)malloc(sizeof(QueueNode));
   124 		} else {
   125 			node = m_FreeNodes.front();
   126 			m_FreeNodes.pop();
   127 		}
   128 
   129 		/* Copy the object */
   130 		new (&node->obj) T(obj);
   131 
   132 		/* Install into the Queue */
   133 		node->prev = m_Head->prev;
   134 		node->next = m_Head;
   135 		m_Head->prev->next = node;
   136 		m_Head->prev = node;
   137 
   138 		m_Size++;
   139 	}
   140 
   141 	size_t size() const
   142 	{
   143 		return m_Size;
   144 	}
   145 
   146 	void clear()
   147 	{
   148 		QueueNode *node = m_Head->next;
   149 		QueueNode *temp;
   150 		m_Head->next = m_Head;
   151 		m_Head->prev = m_Head;
   152 
   153 		// Iterate through the nodes until we find g_Head (the sentinel) again
   154 		while (node != m_Head)
   155 		{
   156 			temp = node->next;
   157 			node->obj.~T();
   158 			m_FreeNodes.push(node);
   159 			node = temp;
   160 		}
   161 		m_Size = 0;
   162 	}
   163 
   164 	bool empty() const
   165 	{
   166 		return (m_Size == 0);
   167 	}
   168 
   169 private:
   170 	QueueNode *m_Head;
   171 	size_t m_Size;
   172 	CStack<QueueNode *> m_FreeNodes;
   173 public:
   174 	class iterator
   175 	{
   176 		friend class Queue;
   177 	public:
   178 		iterator()
   179 		{
   180 			m_This = NULL;
   181 		}
   182 		iterator(const Queue &src)
   183 		{
   184 			m_This = src.m_Head;
   185 		}
   186 		iterator(QueueNode *n) : m_This(n)
   187 		{
   188 		}
   189 		iterator(const iterator &where)
   190 		{
   191 			m_This = where.m_This;
   192 		}
   193 		//pre decrement
   194 		iterator & operator--()
   195 		{
   196 			if (m_This)
   197 				m_This = m_This->prev;
   198 			return *this;
   199 		}
   200 		//post decrement
   201 		iterator operator--(int)
   202 		{
   203 			iterator old(*this);
   204 			if (m_This)
   205 				m_This = m_This->prev;
   206 			return old;
   207 		}	
   208 
   209 		//pre increment
   210 		iterator & operator++()
   211 		{
   212 			if (m_This)
   213 				m_This = m_This->next;
   214 			return *this;
   215 		}
   216 		//post increment
   217 		iterator operator++(int)
   218 		{
   219 			iterator old(*this);
   220 			if (m_This)
   221 				m_This = m_This->next;
   222 			return old;
   223 		}
   224 
   225 		const T & operator * () const
   226 		{
   227 			return m_This->obj;
   228 		}
   229 		T & operator * ()
   230 		{
   231 			return m_This->obj;
   232 		}
   233 
   234 		T * operator -> ()
   235 		{
   236 			return &(m_This->obj);
   237 		}
   238 		const T * operator -> () const
   239 		{
   240 			return &(m_This->obj);
   241 		}
   242 
   243 		bool operator != (const iterator &where) const
   244 		{
   245 			return (m_This != where.m_This);
   246 		}
   247 		bool operator ==(const iterator &where) const
   248 		{
   249 			return (m_This == where.m_This);
   250 		}
   251 	private:
   252 		QueueNode *m_This;
   253 	};
   254 public:
   255 	iterator begin() const
   256 	{
   257 		return iterator(m_Head->next);
   258 	}
   259 
   260 	iterator end() const
   261 	{
   262 		return iterator(m_Head);
   263 	}
   264 
   265 	iterator erase(iterator &where)
   266 	{
   267 		QueueNode *pNode = where.m_This;
   268 		iterator iter(where);
   269 		iter++;
   270 
   271 
   272 		// Works for all cases: empty Queue, erasing first element, erasing tail, erasing in the middle...
   273 		pNode->prev->next = pNode->next;
   274 		pNode->next->prev = pNode->prev;
   275 
   276 		pNode->obj.~T();
   277 		m_FreeNodes.push(pNode);
   278 		m_Size--;
   279 
   280 		return iter;
   281 	}
   282 public:
   283 	void remove(const T & obj)
   284 	{
   285 		iterator b;
   286 		for (b=begin(); b!=end(); b++)
   287 		{
   288 			if ( (*b) == obj )
   289 			{
   290 				erase( b );
   291 				break;
   292 			}
   293 		}
   294 	}
   295 	template <typename U>
   296 	iterator find(const U & equ) const
   297 	{
   298 		iterator iter;
   299 		for (iter=begin(); iter!=end(); iter++)
   300 		{
   301 			if ( (*iter) == equ )
   302 			{
   303 				return iter;
   304 			}
   305 		}
   306 		return end();
   307 	}
   308 	Queue & operator =(const Queue &src)
   309 	{
   310 		clear();
   311 		iterator iter;
   312 		for (iter=src.begin(); iter!=src.end(); iter++)
   313 		{
   314 			push_back( (*iter) );
   315 		}
   316 		return *this;
   317 	}
   318 public:
   319 	T & first() const
   320 	{
   321 		iterator i = begin();
   322 
   323 		return (*i);
   324 	}
   325 
   326 	void pop()
   327 	{
   328 		iterator iter = begin();
   329 		erase(iter);
   330 	}
   331 };
   332 
   333 #endif //_INCLUDE_SM_QUEUE_H