core/sm_queue.h
author Scott Ehlert <ds@alliedmods.net>
Sun Mar 30 07:00:22 2008 +0000 (2008-03-30)
changeset 1952 b7aa2b626807
child 2289 44045ead61cd
permissions -rw-r--r--
Spring Cleaning, Part Ichi (1)
Various minor things done to project files
Updated sample extension project file and updated makefile to the new unified version (more changes likely on the way)
Updated regex project file and makefile
     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 <malloc.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