core/sm_queue.h
author David Anderson <dvander@alliedmods.net>
Thu Jul 19 03:22:10 2007 +0000 (2007-07-19)
changeset 1134 68e8b8d386ff
parent 1099 0c4a41db4436
child 1231 17badaf66ce4
permissions -rw-r--r--
fixed another translator cache issue
     1 /**
     2  * vim: set ts=4 :
     3  * ===============================================================
     4  * SourceMod (C)2004-2007 AlliedModders LLC.  All rights reserved.
     5  * ===============================================================
     6  *
     7  * This file is not open source and may not be copied without explicit
     8  * written permission of AlliedModders LLC.  This file may not be redistributed 
     9  * in whole or significant part.
    10  * For information, see LICENSE.txt or http://www.sourcemod.net/license.php
    11  *
    12  * Version: $Id$
    13  */
    14 
    15 
    16 #ifndef _INCLUDE_SM_QUEUE_H
    17 #define _INCLUDE_SM_QUEUE_H
    18 
    19 #include <new>
    20 #include <malloc.h>
    21 #include <sh_stack.h>
    22 
    23 using namespace SourceHook;
    24 
    25 /*
    26 	A circular, doubly-linked List with one sentinel node
    27 
    28 	Empty:
    29 	m_Head = sentinel
    30 	m_Head->next = m_Head;
    31 	m_Head->prev = m_Head;
    32 	One element:
    33 	m_Head = sentinel
    34 	m_Head->next = node1
    35 	m_Head->prev = node1
    36 	node1->next = m_Head
    37 	node1->prev = m_Head
    38 	Two elements:
    39 	m_Head = sentinel
    40 	m_Head->next = node1
    41 	m_Head->prev = node2
    42 	node1->next = node2
    43 	node1->prev = m_Head
    44 	node2->next = m_Head
    45 	node2->prev = node1
    46 */
    47 template <class T>
    48 class Queue
    49 {
    50 public:
    51 	class iterator;
    52 	friend class iterator;
    53 	class QueueNode
    54 	{
    55 	public:
    56 		T obj;
    57 		QueueNode *next;
    58 		QueueNode *prev;
    59 	};
    60 private:
    61 	// Initializes the sentinel node.
    62 	QueueNode *_Initialize()
    63 	{
    64 		QueueNode *n = (QueueNode *)malloc(sizeof(QueueNode));
    65 		n->next = n;
    66 		n->prev = n;
    67 		return n;
    68 	}
    69 public:
    70 	Queue() : m_Head(_Initialize()), m_Size(0)
    71 	{
    72 	}
    73 
    74 	Queue(const Queue &src) : m_Head(_Initialize()), m_Size(0)
    75 	{
    76 		iterator iter;
    77 		for (iter=src.begin(); iter!=src.end(); iter++)
    78 		{
    79 			push_back( (*iter) );
    80 		}
    81 	}
    82 
    83 	~Queue()
    84 	{
    85 		clear();
    86 
    87 		// Don't forget to free the sentinel
    88 		if (m_Head)
    89 		{
    90 			free(m_Head);
    91 			m_Head = NULL;
    92 		}
    93 
    94 		while (!m_FreeNodes.empty())
    95 		{
    96 			free(m_FreeNodes.front());
    97 			m_FreeNodes.pop();
    98 		}
    99 	}
   100 
   101 	void push(const T &obj)
   102 	{
   103 		QueueNode *node;
   104 		
   105 		if (m_FreeNodes.empty())
   106 		{
   107 			node = (QueueNode *)malloc(sizeof(QueueNode));
   108 		} else {
   109 			node = m_FreeNodes.front();
   110 			m_FreeNodes.pop();
   111 		}
   112 
   113 		/* Copy the object */
   114 		new (&node->obj) T(obj);
   115 
   116 		/* Install into the Queue */
   117 		node->prev = m_Head->prev;
   118 		node->next = m_Head;
   119 		m_Head->prev->next = node;
   120 		m_Head->prev = node;
   121 
   122 		m_Size++;
   123 	}
   124 
   125 	size_t size() const
   126 	{
   127 		return m_Size;
   128 	}
   129 
   130 	void clear()
   131 	{
   132 		QueueNode *node = m_Head->next;
   133 		QueueNode *temp;
   134 		m_Head->next = m_Head;
   135 		m_Head->prev = m_Head;
   136 
   137 		// Iterate through the nodes until we find g_Head (the sentinel) again
   138 		while (node != m_Head)
   139 		{
   140 			temp = node->next;
   141 			node->obj.~T();
   142 			m_FreeNodes.push(node);
   143 			node = temp;
   144 		}
   145 		m_Size = 0;
   146 	}
   147 
   148 	bool empty() const
   149 	{
   150 		return (m_Size == 0);
   151 	}
   152 
   153 private:
   154 	QueueNode *m_Head;
   155 	size_t m_Size;
   156 	CStack<QueueNode *> m_FreeNodes;
   157 public:
   158 	class iterator
   159 	{
   160 		friend class Queue;
   161 	public:
   162 		iterator()
   163 		{
   164 			m_This = NULL;
   165 		}
   166 		iterator(const Queue &src)
   167 		{
   168 			m_This = src.m_Head;
   169 		}
   170 		iterator(QueueNode *n) : m_This(n)
   171 		{
   172 		}
   173 		iterator(const iterator &where)
   174 		{
   175 			m_This = where.m_This;
   176 		}
   177 		//pre decrement
   178 		iterator & operator--()
   179 		{
   180 			if (m_This)
   181 				m_This = m_This->prev;
   182 			return *this;
   183 		}
   184 		//post decrement
   185 		iterator operator--(int)
   186 		{
   187 			iterator old(*this);
   188 			if (m_This)
   189 				m_This = m_This->prev;
   190 			return old;
   191 		}	
   192 
   193 		//pre increment
   194 		iterator & operator++()
   195 		{
   196 			if (m_This)
   197 				m_This = m_This->next;
   198 			return *this;
   199 		}
   200 		//post increment
   201 		iterator operator++(int)
   202 		{
   203 			iterator old(*this);
   204 			if (m_This)
   205 				m_This = m_This->next;
   206 			return old;
   207 		}
   208 
   209 		const T & operator * () const
   210 		{
   211 			return m_This->obj;
   212 		}
   213 		T & operator * ()
   214 		{
   215 			return m_This->obj;
   216 		}
   217 
   218 		T * operator -> ()
   219 		{
   220 			return &(m_This->obj);
   221 		}
   222 		const T * operator -> () const
   223 		{
   224 			return &(m_This->obj);
   225 		}
   226 
   227 		bool operator != (const iterator &where) const
   228 		{
   229 			return (m_This != where.m_This);
   230 		}
   231 		bool operator ==(const iterator &where) const
   232 		{
   233 			return (m_This == where.m_This);
   234 		}
   235 	private:
   236 		QueueNode *m_This;
   237 	};
   238 public:
   239 	iterator begin() const
   240 	{
   241 		return iterator(m_Head->next);
   242 	}
   243 
   244 	iterator end() const
   245 	{
   246 		return iterator(m_Head);
   247 	}
   248 
   249 	iterator erase(iterator &where)
   250 	{
   251 		QueueNode *pNode = where.m_This;
   252 		iterator iter(where);
   253 		iter++;
   254 
   255 
   256 		// Works for all cases: empty Queue, erasing first element, erasing tail, erasing in the middle...
   257 		pNode->prev->next = pNode->next;
   258 		pNode->next->prev = pNode->prev;
   259 
   260 		pNode->obj.~T();
   261 		m_FreeNodes.push(pNode);
   262 		m_Size--;
   263 
   264 		return iter;
   265 	}
   266 public:
   267 	void remove(const T & obj)
   268 	{
   269 		iterator b;
   270 		for (b=begin(); b!=end(); b++)
   271 		{
   272 			if ( (*b) == obj )
   273 			{
   274 				erase( b );
   275 				break;
   276 			}
   277 		}
   278 	}
   279 	template <typename U>
   280 	iterator find(const U & equ) const
   281 	{
   282 		iterator iter;
   283 		for (iter=begin(); iter!=end(); iter++)
   284 		{
   285 			if ( (*iter) == equ )
   286 			{
   287 				return iter;
   288 			}
   289 		}
   290 		return end();
   291 	}
   292 	Queue & operator =(const Queue &src)
   293 	{
   294 		clear();
   295 		iterator iter;
   296 		for (iter=src.begin(); iter!=src.end(); iter++)
   297 		{
   298 			push_back( (*iter) );
   299 		}
   300 		return *this;
   301 	}
   302 public:
   303 	T & first() const
   304 	{
   305 		iterator i = begin();
   306 
   307 		return (*i);
   308 	}
   309 
   310 	void pop()
   311 	{
   312 		iterator iter = begin();
   313 		erase(iter);
   314 	}
   315 };
   316 
   317 #endif //_INCLUDE_SM_QUEUE_H