ds@1952: /**
ds@1952: * vim: set ts=4 :
ds@1952: * =============================================================================
ds@1952: * SourceMod
ds@1952: * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
ds@1952: * =============================================================================
ds@1952: *
ds@1952: * This program is free software; you can redistribute it and/or modify it under
ds@1952: * the terms of the GNU General Public License, version 3.0, as published by the
ds@1952: * Free Software Foundation.
ds@1952: *
ds@1952: * This program is distributed in the hope that it will be useful, but WITHOUT
ds@1952: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
ds@1952: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
ds@1952: * details.
ds@1952: *
ds@1952: * You should have received a copy of the GNU General Public License along with
ds@1952: * this program. If not, see .
ds@1952: *
ds@1952: * As a special exception, AlliedModders LLC gives you permission to link the
ds@1952: * code of this program (as well as its derivative works) to "Half-Life 2," the
ds@1952: * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
ds@1952: * by the Valve Corporation. You must obey the GNU General Public License in
ds@1952: * all respects for all other code used. Additionally, AlliedModders LLC grants
ds@1952: * this exception to all derivative works. AlliedModders LLC defines further
ds@1952: * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
ds@1952: * or .
ds@1952: *
ds@1952: * Version: $Id$
ds@1952: */
ds@1952:
ds@1952: #ifndef _INCLUDE_SM_QUEUE_H
ds@1952: #define _INCLUDE_SM_QUEUE_H
ds@1952:
ds@1952: #include
ds@1952: #include
ds@1952: #include
ds@1952:
ds@1952: using namespace SourceHook;
ds@1952:
ds@1952: /*
ds@1952: A circular, doubly-linked List with one sentinel node
ds@1952:
ds@1952: Empty:
ds@1952: m_Head = sentinel
ds@1952: m_Head->next = m_Head;
ds@1952: m_Head->prev = m_Head;
ds@1952: One element:
ds@1952: m_Head = sentinel
ds@1952: m_Head->next = node1
ds@1952: m_Head->prev = node1
ds@1952: node1->next = m_Head
ds@1952: node1->prev = m_Head
ds@1952: Two elements:
ds@1952: m_Head = sentinel
ds@1952: m_Head->next = node1
ds@1952: m_Head->prev = node2
ds@1952: node1->next = node2
ds@1952: node1->prev = m_Head
ds@1952: node2->next = m_Head
ds@1952: node2->prev = node1
ds@1952: */
ds@1952: template
ds@1952: class Queue
ds@1952: {
ds@1952: public:
ds@1952: class iterator;
ds@1952: friend class iterator;
ds@1952: class QueueNode
ds@1952: {
ds@1952: public:
ds@1952: T obj;
ds@1952: QueueNode *next;
ds@1952: QueueNode *prev;
ds@1952: };
ds@1952: private:
ds@1952: // Initializes the sentinel node.
ds@1952: QueueNode *_Initialize()
ds@1952: {
ds@1952: QueueNode *n = (QueueNode *)malloc(sizeof(QueueNode));
ds@1952: n->next = n;
ds@1952: n->prev = n;
ds@1952: return n;
ds@1952: }
ds@1952: public:
ds@1952: Queue() : m_Head(_Initialize()), m_Size(0)
ds@1952: {
ds@1952: }
ds@1952:
ds@1952: Queue(const Queue &src) : m_Head(_Initialize()), m_Size(0)
ds@1952: {
ds@1952: iterator iter;
ds@1952: for (iter=src.begin(); iter!=src.end(); iter++)
ds@1952: {
ds@1952: push_back( (*iter) );
ds@1952: }
ds@1952: }
ds@1952:
ds@1952: ~Queue()
ds@1952: {
ds@1952: clear();
ds@1952:
ds@1952: // Don't forget to free the sentinel
ds@1952: if (m_Head)
ds@1952: {
ds@1952: free(m_Head);
ds@1952: m_Head = NULL;
ds@1952: }
ds@1952:
ds@1952: while (!m_FreeNodes.empty())
ds@1952: {
ds@1952: free(m_FreeNodes.front());
ds@1952: m_FreeNodes.pop();
ds@1952: }
ds@1952: }
ds@1952:
ds@1952: void push(const T &obj)
ds@1952: {
ds@1952: QueueNode *node;
ds@1952:
ds@1952: if (m_FreeNodes.empty())
ds@1952: {
ds@1952: node = (QueueNode *)malloc(sizeof(QueueNode));
ds@1952: } else {
ds@1952: node = m_FreeNodes.front();
ds@1952: m_FreeNodes.pop();
ds@1952: }
ds@1952:
ds@1952: /* Copy the object */
ds@1952: new (&node->obj) T(obj);
ds@1952:
ds@1952: /* Install into the Queue */
ds@1952: node->prev = m_Head->prev;
ds@1952: node->next = m_Head;
ds@1952: m_Head->prev->next = node;
ds@1952: m_Head->prev = node;
ds@1952:
ds@1952: m_Size++;
ds@1952: }
ds@1952:
ds@1952: size_t size() const
ds@1952: {
ds@1952: return m_Size;
ds@1952: }
ds@1952:
ds@1952: void clear()
ds@1952: {
ds@1952: QueueNode *node = m_Head->next;
ds@1952: QueueNode *temp;
ds@1952: m_Head->next = m_Head;
ds@1952: m_Head->prev = m_Head;
ds@1952:
ds@1952: // Iterate through the nodes until we find g_Head (the sentinel) again
ds@1952: while (node != m_Head)
ds@1952: {
ds@1952: temp = node->next;
ds@1952: node->obj.~T();
ds@1952: m_FreeNodes.push(node);
ds@1952: node = temp;
ds@1952: }
ds@1952: m_Size = 0;
ds@1952: }
ds@1952:
ds@1952: bool empty() const
ds@1952: {
ds@1952: return (m_Size == 0);
ds@1952: }
ds@1952:
ds@1952: private:
ds@1952: QueueNode *m_Head;
ds@1952: size_t m_Size;
ds@1952: CStack m_FreeNodes;
ds@1952: public:
ds@1952: class iterator
ds@1952: {
ds@1952: friend class Queue;
ds@1952: public:
ds@1952: iterator()
ds@1952: {
ds@1952: m_This = NULL;
ds@1952: }
ds@1952: iterator(const Queue &src)
ds@1952: {
ds@1952: m_This = src.m_Head;
ds@1952: }
ds@1952: iterator(QueueNode *n) : m_This(n)
ds@1952: {
ds@1952: }
ds@1952: iterator(const iterator &where)
ds@1952: {
ds@1952: m_This = where.m_This;
ds@1952: }
ds@1952: //pre decrement
ds@1952: iterator & operator--()
ds@1952: {
ds@1952: if (m_This)
ds@1952: m_This = m_This->prev;
ds@1952: return *this;
ds@1952: }
ds@1952: //post decrement
ds@1952: iterator operator--(int)
ds@1952: {
ds@1952: iterator old(*this);
ds@1952: if (m_This)
ds@1952: m_This = m_This->prev;
ds@1952: return old;
ds@1952: }
ds@1952:
ds@1952: //pre increment
ds@1952: iterator & operator++()
ds@1952: {
ds@1952: if (m_This)
ds@1952: m_This = m_This->next;
ds@1952: return *this;
ds@1952: }
ds@1952: //post increment
ds@1952: iterator operator++(int)
ds@1952: {
ds@1952: iterator old(*this);
ds@1952: if (m_This)
ds@1952: m_This = m_This->next;
ds@1952: return old;
ds@1952: }
ds@1952:
ds@1952: const T & operator * () const
ds@1952: {
ds@1952: return m_This->obj;
ds@1952: }
ds@1952: T & operator * ()
ds@1952: {
ds@1952: return m_This->obj;
ds@1952: }
ds@1952:
ds@1952: T * operator -> ()
ds@1952: {
ds@1952: return &(m_This->obj);
ds@1952: }
ds@1952: const T * operator -> () const
ds@1952: {
ds@1952: return &(m_This->obj);
ds@1952: }
ds@1952:
ds@1952: bool operator != (const iterator &where) const
ds@1952: {
ds@1952: return (m_This != where.m_This);
ds@1952: }
ds@1952: bool operator ==(const iterator &where) const
ds@1952: {
ds@1952: return (m_This == where.m_This);
ds@1952: }
ds@1952: private:
ds@1952: QueueNode *m_This;
ds@1952: };
ds@1952: public:
ds@1952: iterator begin() const
ds@1952: {
ds@1952: return iterator(m_Head->next);
ds@1952: }
ds@1952:
ds@1952: iterator end() const
ds@1952: {
ds@1952: return iterator(m_Head);
ds@1952: }
ds@1952:
ds@1952: iterator erase(iterator &where)
ds@1952: {
ds@1952: QueueNode *pNode = where.m_This;
ds@1952: iterator iter(where);
ds@1952: iter++;
ds@1952:
ds@1952:
ds@1952: // Works for all cases: empty Queue, erasing first element, erasing tail, erasing in the middle...
ds@1952: pNode->prev->next = pNode->next;
ds@1952: pNode->next->prev = pNode->prev;
ds@1952:
ds@1952: pNode->obj.~T();
ds@1952: m_FreeNodes.push(pNode);
ds@1952: m_Size--;
ds@1952:
ds@1952: return iter;
ds@1952: }
ds@1952: public:
ds@1952: void remove(const T & obj)
ds@1952: {
ds@1952: iterator b;
ds@1952: for (b=begin(); b!=end(); b++)
ds@1952: {
ds@1952: if ( (*b) == obj )
ds@1952: {
ds@1952: erase( b );
ds@1952: break;
ds@1952: }
ds@1952: }
ds@1952: }
ds@1952: template
ds@1952: iterator find(const U & equ) const
ds@1952: {
ds@1952: iterator iter;
ds@1952: for (iter=begin(); iter!=end(); iter++)
ds@1952: {
ds@1952: if ( (*iter) == equ )
ds@1952: {
ds@1952: return iter;
ds@1952: }
ds@1952: }
ds@1952: return end();
ds@1952: }
ds@1952: Queue & operator =(const Queue &src)
ds@1952: {
ds@1952: clear();
ds@1952: iterator iter;
ds@1952: for (iter=src.begin(); iter!=src.end(); iter++)
ds@1952: {
ds@1952: push_back( (*iter) );
ds@1952: }
ds@1952: return *this;
ds@1952: }
ds@1952: public:
ds@1952: T & first() const
ds@1952: {
ds@1952: iterator i = begin();
ds@1952:
ds@1952: return (*i);
ds@1952: }
ds@1952:
ds@1952: void pop()
ds@1952: {
ds@1952: iterator iter = begin();
ds@1952: erase(iter);
ds@1952: }
ds@1952: };
ds@1952:
ds@1952: #endif //_INCLUDE_SM_QUEUE_H