ScummVM API documentation
list.h
1 
2 /* ScummVM - Graphic Adventure Engine
3  *
4  * ScummVM is the legal property of its developers, whose names
5  * are too numerous to list here. Please refer to the COPYRIGHT
6  * file distributed with this source distribution.
7  *
8  * This program is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program. If not, see <http://www.gnu.org/licenses/>.
20  *
21  */
22 
23 #ifndef BAGEL_BOFLIB_LIST_H
24 #define BAGEL_BOFLIB_LIST_H
25 
26 #include "common/scummsys.h"
27 #include "bagel/boflib/misc.h"
28 
29 namespace Bagel {
30 
31 
32 #define MIN_NODES 5 // Minimum # of pre-allocated nodes in node array
33 
34 template<class T>
35 class CBofListNode {
36 protected:
37  T _cItem; // Data contained at this node
38 
39 public:
40  CBofListNode() {
41  _pNext = _pPrev = nullptr;
42  }
43  CBofListNode(T cItem) {
44  _pNext = _pPrev = nullptr;
45  _cItem = cItem;
46  }
47 
48  T getNodeItem() {
49  return _cItem;
50  }
51  void setNodeItem(T cItem) {
52  _cItem = cItem;
53  }
54 
55  CBofListNode *_pNext; // Next node in list
56  CBofListNode *_pPrev; // Previous node in list
57 };
58 
59 template<class T>
60 class CBofList {
61 private:
62  void newItemList() {
63  if (_pItemList != nullptr) {
64  bofFree(_pItemList);
65  _pItemList = nullptr;
66  }
67 
68  if (_nNumItems != 0) {
69  _pItemList = (void **)bofAlloc(_nNumItems * sizeof(void *));
70  }
71  }
72 
73  void killItemList() {
74  if (_pItemList != nullptr) {
75  bofFree(_pItemList);
76  _pItemList = nullptr;
77  }
78  }
79 
80  void recalcItemList() {
81  // We only want to recalc if we're about to overflow what we have
82  if (_nNumItems >= _nItemsAllocated) {
83  if (_pItemList != nullptr) {
84  bofFree(_pItemList);
85  _pItemList = nullptr;
86  }
87 
88  if (_nNumItems != 0) {
89  assert(_nItemsAllocated < 0x8000);
90  _nItemsAllocated *= 2;
91  if (_nItemsAllocated == 0)
92  _nItemsAllocated = MIN_NODES;
93 
94  _pItemList = (void **)bofAlloc(_nItemsAllocated * sizeof(void *));
95  }
96  }
97 
98  if (_nNumItems != 0) {
99  assert(_pItemList != nullptr);
100 
101  int i = 0;
102  CBofListNode<T> *pNode = _pHead;
103 
104  while (pNode != nullptr) {
105  *(_pItemList + i++) = pNode;
106  pNode = pNode->_pNext;
107  }
108  }
109  }
110 
116  CBofListNode<T> *newNode(T cItem) {
117  CBofListNode<T> *pNewNode = new CBofListNode<T>(cItem);
118  return pNewNode;
119  }
120 
127  CBofListNode<T> *getActualHead() {
128  CBofListNode<T> *pNode;
129  CBofListNode<T> *pLast = pNode = _pHead;
130 
131  while (pNode != nullptr) {
132  pLast = pNode;
133  pNode = pNode->_pPrev;
134  }
135 
136  return pLast;
137  }
138 
145  CBofListNode<T> *getActualTail() {
146  CBofListNode<T> *pNode;
147  CBofListNode<T> *pLast = pNode = _pTail;
148 
149  while (pNode != nullptr) {
150  pLast = pNode;
151  pNode = pLast->_pNext;
152  }
153 
154  return pLast;
155  }
156 
157 protected:
158  uint32 _nNumItems;
159  uint32 _nItemsAllocated;
160  CBofListNode<T> *_pHead; // pointer to head of list
161  CBofListNode<T> *_pTail; // pointer to tail of list
162 
163  void **_pItemList; // pointer to secondary node list
164 
165 public:
166  /*
167  * Constructor
168  */
169  CBofList() {
170  _nNumItems = 0;
171  _nItemsAllocated = 0;
172  _pHead = _pTail = nullptr;
173  _pItemList = nullptr;
174  }
175 
179  virtual ~CBofList() {
180  removeAll();
181  killItemList();
182  assert(_nNumItems == 0);
183  }
184 
185  int getCount() const {
186  return _nNumItems;
187  }
188 
193  int getActualCount() const {
194  uint32 nCount = 0;
195  CBofListNode<T> *pNode = _pHead;
196  while (pNode != nullptr) {
197  nCount++;
198  pNode = pNode->_pNext;
199  }
200 
201  // There should be no discrepancy
202  assert(_nNumItems == nCount);
203 
204  return _nNumItems;
205  }
206 
211  bool isEmpty() const {
212  return _pHead == nullptr;
213  }
214 
220  inline T getNodeItem(int nNodeIndex) {
221  CBofListNode<T> *pNode = getNode(nNodeIndex);
222 
223  assert(pNode != nullptr);
224 
225  return pNode->getNodeItem();
226  }
227 
228  void setNodeItem(int nNodeIndex, T tNewItem) {
229  CBofListNode<T> *pNode = getNode(nNodeIndex);
230 
231  assert(pNode != nullptr);
232 
233  pNode->setNodeItem(tNewItem);
234  }
235 
236  T operator[](int nIndex) {
237  return getNodeItem(nIndex);
238  }
239 
245  CBofListNode<T> *getNode(int nNodeIndex) {
246  assert(nNodeIndex >= 0 && nNodeIndex < getCount());
247 
248  CBofListNode<T> *pNode;
249 
250  if (_pItemList == nullptr) {
251 
252  pNode = _pHead;
253  while (pNode != nullptr) {
254  if (nNodeIndex-- == 0)
255  break;
256  pNode = pNode->_pNext;
257  }
258 
259  } else {
260  pNode = (CBofListNode<T> *)(*(_pItemList + nNodeIndex));
261  }
262 
263  return pNode;
264  }
265 
271  void insertBefore(int nNodeIndex, T cNewItem) {
272  assert(!isEmpty());
273  insertBefore(getNode(nNodeIndex), cNewItem);
274  }
275 
281  void insertBefore(CBofListNode<T> *pNode, T cNewItem) {
282  assert(pNode != nullptr);
283  assert(!isEmpty());
284 
285  if (pNode == _pHead) {
286  addToHead(cNewItem);
287  } else {
288 
289  CBofListNode<T> *pNewNode = newNode(cNewItem);
290 
291  pNewNode->_pPrev = pNode->_pPrev;
292  pNewNode->_pNext = pNode;
293 
294  if (pNode->_pPrev != nullptr)
295  pNode->_pPrev->_pNext = pNewNode;
296 
297  pNode->_pPrev = pNewNode;
298  }
299 
300  // one more item in list
301  assert(_nNumItems != 0xFFFF);
302  _nNumItems++;
303 
304  recalcItemList();
305  }
306 
312  void insertAfter(int nNodeIndex, T cNewItem) {
313  assert(!isEmpty());
314  insertAfter(getNode(nNodeIndex), cNewItem);
315  }
316 
322  void insertAfter(CBofListNode<T> *pNode, T cNewItem) {
323  assert(pNode != nullptr);
324  assert(!isEmpty());
325 
326  if (pNode == _pTail) {
327  addToTail(cNewItem);
328  } else {
329 
330  CBofListNode<T> *pNewNode = newNode(cNewItem);
331  pNewNode->_pPrev = pNode;
332  pNewNode->_pNext = pNode->_pNext;
333 
334  if (pNode->_pNext != nullptr)
335  pNode->_pNext->_pPrev = pNewNode;
336 
337  pNode->_pNext = pNewNode;
338  }
339 
340  // one more item in list
341  assert(_nNumItems != 0xFFFF);
342  _nNumItems++;
343 
344  recalcItemList();
345  }
346 
352  T remove(CBofListNode<T> *pNode) {
353  assert(pNode != nullptr);
354 
355  // One less item in list
356  _nNumItems--;
357 
358  //assert(_nNumItems >= 0);
359 
360  if (pNode != nullptr) {
361 
362  T retVal = pNode->getNodeItem();
363 
364  if (_pHead == pNode)
365  _pHead = _pHead->_pNext;
366 
367  if (_pTail == pNode)
368  _pTail = _pTail->_pPrev;
369 
370  if (pNode->_pPrev != nullptr)
371  pNode->_pPrev->_pNext = pNode->_pNext;
372 
373  if (pNode->_pNext != nullptr)
374  pNode->_pNext->_pPrev = pNode->_pPrev;
375 
376  delete pNode;
377 
378  recalcItemList();
379  return retVal;
380  } else {
381  return T();
382  }
383  }
384 
390  T remove(int nNodeIndex) {
391  return remove(getNode(nNodeIndex));
392  }
393 
398  void removeAll() {
399  int i = getCount();
400 
401  while (i-- != 0)
402  remove(0);
403  }
404 
409  inline T removeHead() {
410  assert(_pHead != nullptr);
411 
412  return remove(_pHead);
413  }
414 
419  inline T removeTail() {
420  assert(_pTail != nullptr);
421  return remove(_pTail);
422  }
423 
428  inline void addToHead(CBofListNode<T> *pNewNode) {
429  assert(pNewNode != nullptr);
430 
431  pNewNode->_pNext = _pHead;
432  pNewNode->_pPrev = nullptr;
433  if (_pHead != nullptr)
434  _pHead->_pPrev = pNewNode;
435  _pHead = pNewNode;
436 
437  if (_pTail == nullptr)
438  _pTail = _pHead;
439 
440  // one less item in list
441  assert(_nNumItems != 0xFFFF);
442  _nNumItems++;
443 
444  recalcItemList();
445  }
446 
451  inline void addToHead(T cItem) {
452  addToHead(newNode(cItem));
453  }
454 
459  void addToTail(CBofListNode<T> *pNewNode) {
460  assert(pNewNode != nullptr);
461 
462  pNewNode->_pPrev = _pTail;
463  pNewNode->_pNext = nullptr;
464  if (_pTail != nullptr)
465  _pTail->_pNext = pNewNode;
466  _pTail = pNewNode;
467 
468  if (_pHead == nullptr)
469  _pHead = _pTail;
470 
471  // One more item in list
472  assert(_nNumItems != 0xFFFF);
473  _nNumItems++;
474  recalcItemList();
475  }
476 
481  void addToTail(T cItem) {
482  addToTail(newNode(cItem));
483  }
484 
485  CBofListNode<T> *getHead() const {
486  return _pHead;
487  }
488  CBofListNode<T> *getTail() const {
489  return _pTail;
490  }
491 };
492 
493 } // namespace Bagel
494 
495 #endif
void insertBefore(CBofListNode< T > *pNode, T cNewItem)
Definition: list.h:281
T removeHead()
Definition: list.h:409
void removeAll()
Definition: list.h:398
T removeTail()
Definition: list.h:419
void insertAfter(int nNodeIndex, T cNewItem)
Definition: list.h:312
void insertAfter(CBofListNode< T > *pNode, T cNewItem)
Definition: list.h:322
void addToTail(T cItem)
Definition: list.h:481
void addToHead(CBofListNode< T > *pNewNode)
Definition: list.h:428
int getActualCount() const
Definition: list.h:193
Definition: bagel.h:31
void addToTail(CBofListNode< T > *pNewNode)
Definition: list.h:459
Definition: list.h:60
virtual ~CBofList()
Definition: list.h:179
bool isEmpty() const
Definition: list.h:211
void insertBefore(int nNodeIndex, T cNewItem)
Definition: list.h:271
T getNodeItem(int nNodeIndex)
Definition: list.h:220
Definition: list.h:35
CBofListNode< T > * getNode(int nNodeIndex)
Definition: list.h:245
void addToHead(T cItem)
Definition: list.h:451