CTR Pia  4.11.3
Game Communication Engine
common_ObjList.h
1 /*---------------------------------------------------------------------------*
2  Project: Pia
3  File: common_ObjList.h
4 
5  Copyright Nintendo. All rights reserved.
6 
7  These coded instructions, statements, and computer programs contain
8  proprietary information of Nintendo of America Inc. and/or Nintendo
9  Company Ltd., and are protected by Federal copyright law. They may
10  not be disclosed to third parties or copied or duplicated in any form,
11  in whole or in part, without the prior written consent of Nintendo.
12  *---------------------------------------------------------------------------*/
13 
14 
15 #pragma once
16 
17 #include <pia/common/common_definitions.h>
18 #include <pia/common/common_OffsetList.h>
19 
20 
21 namespace nn
22 {
23 namespace pia
24 {
25 namespace common
26 {
27 
28 
29 /*!
30 @cond PRIVATE
31 @brief Represents a doubly linked list used to manage memory for storing objects.
32 
33 @details Before using the list, call the <tt>SetBuffer</tt> function and set the memory to use.
34 
35 @param T Specifies the type of object being managed.
36 */
37 template <typename T>
38 class ObjList : public nn::pia::common::ListBase
39 {
40 protected:
41  struct Node
42  {
43  public:
44  Node()
45  : m_Item()
46  {
47  }
48  Node(const Node& n)
49  : m_Item(n.m_Item)
50  {
51  }
52 
53  public:
54  ListNode m_Link;
55  T m_Item;
56  };
57 
58  enum
59  {
60  c_LinkOffset = offsetof(Node, m_Link),
61  c_ItemOffset = offsetof(Node, m_Item)
62  };
63 
64 public:
65 /*!
66 @brief Represents the type of object being stored in the list.
67 */
68  typedef T ValueType;
69 
70  enum
71  {
72 /*!
73 @brief Specifies the size of the element management class.
74 
75 @details The class uses a buffer of the size given by <tt>c_NodeSize * (max_number_of_elements)</tt>.
76 */
77  c_NodeSize = sizeof(Node)
78  };
79 
80 
81 /*!
82 @brief Instantiates the object with default parameters (default constructor).
83 */
84  ObjList()
85  : ListBase(), m_FreeList(), m_pBuffer(NULL), m_LimitNum(0)
86  {
87  m_FreeList.InitOffset(offsetof(Node, m_Link));
88  }
89 
90 
91 /*!
92 @brief Gets the required buffer size.
93 
94 @return Returns the required buffer size.
95 */
96  static u32 GetNeedBufferSize(u32 limitNum)
97  {
98  return limitNum * c_NodeSize;
99  }
100 
101 
102 /*!
103 @brief Sets the memory used to store the objects.
104 
105 @details Memory of the size specified by <tt>GetNeedBufferSize(limitNum)</tt> (that is, <tt>limitNum * c_NodeSize</tt>) is required.
106 
107 @param limitNum Specifies the maximum number of elements to store in the list.
108 @param pBuffer Specifies the address of the memory used by the list.
109 */
110  void SetBuffer(u32 limitNum, void* pBuffer)
111  {
112  if (limitNum > 0)
113  {
114  if (pBuffer != NULL)
115  {
116  m_pBuffer = reinterpret_cast<Node*>(pBuffer);
117  m_LimitNum = limitNum;
118  for (u32 i = 0; i < limitNum; ++i)
119  {
120  new (&m_pBuffer[i].m_Link) ListNode();
121  m_FreeList.PushBack(&m_pBuffer[i]);
122  }
123  }
124  else
125  {
126  PIA_ASSERTMSG(false, "pBuf is null");
127  }
128  }
129  else
130  {
131  PIA_ASSERTMSG(false, "limitNum[%d] must be larger than zero", limitNum);
132  }
133  }
134 
135 
136 /*!
137 @brief Gets whether a buffer has been set.
138 
139 @return Returns <tt>true</tt> if a buffer has been set.
140 */
141  bool IsBufferReady() const
142  {
143  return m_pBuffer != NULL;
144  }
145 
146 
147 /*!
148 @brief Gets the maximum number of elements that can be stored in the list.
149 
150 @return Returns the maximum number of elements that can be stored in the list.
151 */
152  u32 MaxSize() const
153  {
154  return m_LimitNum;
155  }
156 
157 
158 /*!
159 @brief Gets whether the number of elements in the list has reached the maximum.
160 
161 @return Returns <tt>true</tt> if the number of elements in the list has reached the maximum.
162 */
163  bool IsFull() const
164  {
165  return m_FreeList.IsEmpty();
166  }
167 
168 
169 /*!
170 @brief Deletes all elements.
171 
172 @details The function calls the destructor on all stored elements.
173 */
174  void Clear()
175  {
176  ListNode* pNode = Terminator()->Next();
177  while (pNode != Terminator())
178  {
179  ListNode* pN = pNode;
180  pNode = pNode->Next();
181  InitListNode(pN);
182  m_FreeList.PushFront(ListNodeToNode(pN));
183  }
184  Init();
185  }
186 
187 
188 /*!
189 @brief Creates an element and appends it to the end of the list.
190 
191 @details If the number of elements being stored has reached the maximum, the release version returns <tt>NULL</tt>, and other versions assert.
192 
193 @return Returns the element that was added.
194 */
195  T* BirthBack()
196  {
197  if (IsFull())
198  {
199  PIA_ASSERTMSG(false, "buffer full");
200  return NULL;
201  }
202  Node* pNode = m_FreeList.PopBack();
203  new (&pNode->m_Item) T();
204  PushBackNode(&(pNode->m_Link));
205  return &(pNode->m_Item);
206  }
207 
208 
209 /*!
210 @brief Creates an element and appends it to the end of the list.
211 
212 @details The function returns <tt>NULL</tt> if the number of elements being stored has reached the maximum.
213 
214 @return Returns the element that was added.
215 */
216  T* TryBirthBack()
217  {
218  if (IsFull())
219  {
220  return NULL;
221  }
222  Node* pNode = m_FreeList.PopBack();
223  new (&pNode->m_Item) T();
224  PushBackNode(&(pNode->m_Link));
225  return &(pNode->m_Item);
226  }
227 
228 
229 /*!
230 @brief Creates an element and adds it to the start of the list.
231 
232 @details If the number of elements being stored has reached the maximum, the release version returns <tt>NULL</tt>, and other versions assert.
233 
234 @return Returns the element that was added.
235 */
236  T* BirthFront()
237  {
238  if (IsFull())
239  {
240  PIA_ASSERTMSG(false, "buffer full");
241  return NULL;
242  }
243  Node* pNode = m_FreeList.PopBack();
244  new (&pNode->m_Item) T();
245  PushFrontNode(&(pNode->m_Link));
246  return &(pNode->m_Item);
247  }
248 
249 
250 /*!
251 @brief Creates an element and adds it to the start of the list.
252 
253 @details The function returns <tt>NULL</tt> if the number of elements being stored has reached the maximum.
254 
255 @return Returns the element that was added.
256 */
257  T* TryBirthFront()
258  {
259  if (IsFull())
260  {
261  return NULL;
262  }
263  Node* pNode = m_FreeList.PopBack();
264  new (&pNode->m_Item) T();
265  PushFrontNode(&(pNode->m_Link));
266  return &(pNode->m_Item);
267  }
268 
269 
270 /*!
271 @brief Creates an element and inserts it in front of the specified element.
272 
273 @details If the number of elements being stored has reached the maximum, the release version returns <tt>NULL</tt>, and other versions assert.
274 
275 @param pBasis Specifies the base element.
276 
277 @return Returns the element that was added.
278 */
279  T* BirthBefore(const T* pBasis)
280  {
281  if (IsFull())
282  {
283  PIA_ASSERTMSG(false, "buffer full");
284  return NULL;
285  }
286  Node* pNode = m_FreeList.PopBack();
287  new (&pNode->m_Item) T();
288  InsertBeforeNode(&(ObjToNode(pBasis)->m_Link), &(pNode->m_Link));
289  return &(pNode->m_Item);
290  }
291 
292 
293 /*!
294 @brief Creates an element and inserts it in front of the specified element.
295 
296 @details The function returns <tt>NULL</tt> if the number of elements being stored has reached the maximum.
297 
298 @param pBasis Specifies the base element.
299 
300 @return Returns the element that was added.
301 */
302  T* TryBirthBefore(const T* pBasis)
303  {
304  if (IsFull())
305  {
306  return NULL;
307  }
308  Node* pNode = m_FreeList.PopBack();
309  new (&pNode->m_Item) T();
310  InsertBeforeNode(&(ObjToNode(pBasis)->m_Link), &(pNode->m_Link));
311  return &(pNode->m_Item);
312  }
313 
314 
315 /*!
316 @brief Creates an element and inserts it after the specified element.
317 
318 @details If the number of elements being stored has reached the maximum, the release version returns <tt>NULL</tt>, and other versions assert.
319 
320 @param pBasis Specifies the base element.
321 
322 @return Returns the element that was added.
323 */
324  T* BirthAfter(const T* pBasis)
325  {
326  if (IsFull())
327  {
328  PIA_ASSERTMSG(false, "buffer full");
329  return NULL;
330  }
331  Node* pNode = m_FreeList.PopBack();
332  new (&pNode->m_Item) T();
333  InsertAfterNode(&(ObjToNode(pBasis)->m_Link), &(pNode->m_Link));
334  return &(pNode->m_Item);
335  }
336 
337 
338 /*!
339 @brief Creates an element and inserts it after the specified element.
340 
341 @details The function returns <tt>NULL</tt> if the number of elements being stored has reached the maximum.
342 
343 @param pBasis Specifies the base element.
344 
345 @return Returns the element that was added.
346 */
347  T* TryBirthAfter(const T* pBasis)
348  {
349  if (IsFull())
350  {
351  return NULL;
352  }
353  Node* pNode = m_FreeList.PopBack();
354  new (&pNode->m_Item) T();
355  InsertAfterNode(&(ObjToNode(pBasis)->m_Link), &(pNode->m_Link));
356  return &(pNode->m_Item);
357  }
358 
359 
360 /*!
361 @brief Removes the specified element.
362 
363 @details Operations are undefined if the specified element is not in the list.
364 
365 @param pObj Specifies the element to remove.
366 */
367  void Erase(T* pObj)
368  {
369  Node* pNode = ObjToNode(pObj);
370  pObj->~T();
371  EraseNode(&(pNode->m_Link));
372  m_FreeList.PushFront(pNode);
373  }
374 
375 
376 /*!
377 @brief Gets the element at the start of the list.
378 
379 @return Returns the element at the start of the list.
380 Returns <tt>NULL</tt> if the list is empty.
381 */
382  T* Front()
383  {
384  ListNode* pLink = FrontNode();
385  if (pLink == NULL)
386  {
387  return NULL;
388  }
389  return &(ListNodeToNode(pLink)->m_Item);
390  }
391 
392 
393 /*!
394 @brief Gets the last element in the list.
395 
396 @return Returns the last element in the list.
397 Returns <tt>NULL</tt> if the list is empty.
398 */
399  T* Back()
400  {
401  ListNode* pLink = BackNode();
402  if (pLink == NULL)
403  {
404  return NULL;
405  }
406  return &(ListNodeToNode(pLink)->m_Item);
407  }
408 
409 
410 /*!
411 @brief Gets the element before the specified element.
412 
413 @param pObj Specifies the base element.
414 Operations are undefined if the specified element is not in the list.
415 
416 @return Returns the element before the specified element.
417 Returns <tt>NULL</tt> if the first element in the list is specified as the base.
418 */
419  T* Prev(const T* pObj)
420  {
421  ListNode* pPrevLink = ObjToNode(pObj)->m_Link.Prev();
422  if (pPrevLink == Terminator())
423  {
424  return NULL;
425  }
426  return &(ListNodeToNode(pPrevLink)->m_Item);
427  }
428 
429 
430 /*!
431 @brief Gets the element after the specified element.
432 
433 @param pObj Specifies the base element.
434 Operations are undefined if the specified element is not in the list.
435 
436 @return Returns the element after the specified element.
437 Returns <tt>NULL</tt> if the last element in the list is specified as the base.
438 */
439  T* Next(const T* pObj)
440  {
441  ListNode* pNextLink = ObjToNode(pObj)->m_Link.Next();
442  if (pNextLink == Terminator())
443  {
444  return NULL;
445  }
446  return &(ListNodeToNode(pNextLink)->m_Item);
447  }
448 
449 
450 /*!
451 @brief Checks whether the specified element is in the list.
452 
453 @param pObj Specifies the element to check.
454 
455 @return Returns <tt>true</tt> if the element is in the list.
456 */
457  bool IsInclude(const T* pObj) const
458  {
459  return IsIncludeNode(&(ObjToNode(pObj)->m_Link));
460  }
461 
462 
463 /*!
464 @brief Represents an iterator for the <tt>ObjList</tt> class.
465 */
466  class Iterator
467  {
468  friend class ObjList<T>;
469 
470  private:
471  Iterator(const ObjList<T>* pList, typename ObjList<T>::Node* pNode)
472  : m_pList(pList), m_pNode(pNode)
473  {
474  }
475 
476  public:
477  Iterator& operator++()
478  {
479  m_pNode = m_pList->ListNodeToNode(m_pNode->m_Link.Next());
480  return *this;
481  }
482 
483  bool operator==(const Iterator& x) const
484  {
485  return m_pNode == x.m_pNode;
486  }
487  bool operator!=(const Iterator& x) const
488  {
489  return m_pNode != x.m_pNode;
490  }
491 
492  T& operator*()
493  {
494  return m_pNode->m_Item;
495  }
496  T* operator->()
497  {
498  return &(m_pNode->m_Item);
499  }
500 
501  private:
502  const ObjList<T>* m_pList;
503  typename ObjList<T>::Node* m_pNode;
504  };
505 
506 
507 /*!
508 @brief Represents a <tt>const</tt> iterator for the <tt>ObjList</tt> class.
509 */
510  class ConstIterator
511  {
512  friend class ObjList<T>;
513 
514  private:
515  ConstIterator(const ObjList<T>* pList, typename ObjList<T>::Node* pNode)
516  : m_pList(pList), m_pNode(pNode)
517  {
518  }
519 
520  public:
521  ConstIterator& operator++()
522  {
523  m_pNode = m_pList->ListNodeToNode(m_pNode->m_Link.Next());
524  return *this;
525  }
526 
527  bool operator==(const ConstIterator& x) const
528  {
529  return m_pNode == x.m_pNode;
530  }
531  bool operator!=(const ConstIterator& x) const
532  {
533  return m_pNode != x.m_pNode;
534  }
535 
536  const T& operator*() const
537  {
538  return m_pNode->m_Item;
539  }
540  const T* operator->() const
541  {
542  return &(m_pNode->m_Item);
543  }
544 
545  private:
546  const ObjList<T>* m_pList;
547  typename ObjList<T>::Node* m_pNode;
548  };
549 
550 
551 /*!
552 @brief Represents a <tt>robust</tt> iterator for the <tt>ObjList</tt> class.
553 
554 @details The iterator remains valid even if the element it points to is removed.
555 The iterator is no longer valid if an element is added or an element it does not point to is removed.
556 */
557  class RobustIterator
558  {
559  friend class ObjList<T>;
560 
561  private:
562  RobustIterator(const ObjList<T>* pList, typename ObjList<T>::Node* pNode)
563  : m_pList(pList), m_pNode(pNode)
564  {
565  m_pNextLink = m_pNode->m_Link.Next();
566  }
567 
568  public:
569  RobustIterator& operator++()
570  {
571  m_pNode = m_pList->ListNodeToNode(m_pNextLink);
572  m_pNextLink = m_pNode->m_Link.Next();
573  return *this;
574  }
575 
576  bool operator==(const RobustIterator& x) const
577  {
578  return m_pNode == x.m_pNode;
579  }
580  bool operator!=(const RobustIterator& x) const
581  {
582  return m_pNode != x.m_pNode;
583  }
584 
585  T& operator*()
586  {
587  return m_pNode->m_Item;
588  }
589  T* operator->()
590  {
591  return &(m_pNode->m_Item);
592  }
593 
594  private:
595  const ObjList<T>* m_pList;
596  typename ObjList<T>::Node* m_pNode;
597  ListNode* m_pNextLink;
598  };
599 
600 
601 /*!
602 @brief Gets an Iterator pointing to the element at the start of the list.
603 
604 @return Returns an iterator pointing to the element at the start of the list.
605 */
606  Iterator Begin() const
607  {
608  return Iterator(this, ListNodeToNode(Terminator()->Next()));
609  }
610 
611 
612 /*!
613 @brief Gets an <tt>Iterator</tt> object pointing to the element after the last element in the list.
614 
615 @return Returns an <tt>Iterator</tt> object pointing to the element after the last element in the list.
616 */
617  Iterator End() const
618  {
619  return Iterator(this, ListNodeToNode(Terminator()));
620  }
621 
622 
623 /*!
624 @brief Gets a <tt>const</tt> iterator pointing to the element at the start of the list.
625 
626 @return Returns a <tt>ConstIterator</tt> object pointing to the element at the start of the list.
627 */
628  ConstIterator ConstBegin() const
629  {
630  return ConstIterator(this, ListNodeToNode(Terminator()->Next()));
631  }
632 
633 
634 /*!
635 @brief Gets a <tt>const</tt> iterator pointing to the element after the last element in the list.
636 
637 @return Returns a <tt>ConstIterator</tt> object pointing to the element after the last element in the list.
638 */
639  ConstIterator ConstEnd() const
640  {
641  return ConstIterator(this, ListNodeToNode(Terminator()));
642  }
643 
644 
645 /*!
646 @brief Gets a <tt>RobustIterator</tt> object pointing to the element at the start of the list.
647 
648 @return Returns a <tt>RobustIterator</tt> object pointing to the element at the start of the list.
649 */
650  RobustIterator RobustBegin() const
651  {
652  return RobustIterator(this, ListNodeToNode(Terminator()->Next()));
653  }
654 
655 
656 /*!
657 @brief Gets a <tt>RobustIterator</tt> object pointing to the element after the last element in the list.
658 
659 @return Returns a <tt>RobustIterator</tt> object pointing to the element after the last element in the list.
660 */
661  RobustIterator RobustEnd() const
662  {
663  return RobustIterator(this, ListNodeToNode(Terminator()));
664  }
665 
666 private:
667  static Node* ObjToNode(const T* pObj)
668  {
669  return reinterpret_cast<Node*>((reinterpret_cast<u32>(pObj)) - c_ItemOffset);
670  }
671 
672  static Node* ListNodeToNode(const ListNode* pListNode)
673  {
674  return reinterpret_cast<Node*>((reinterpret_cast<u32>(pListNode)) - c_LinkOffset);
675  }
676 
677 
678 private:
679  OffsetList<Node> m_FreeList;
680  Node* m_pBuffer;
681  u32 m_LimitNum;
682 };
683 //! @endcond
684 }
685 }
686 } // end of namespace nn::pia::common
Definition: assert.h:115