SourceMod SDK  1.7
sm_queue.h
1 
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
Definition: sm_queue.h:64
Definition: sm_queue.h:174
Definition: sm_queue.h:69