CTR-Pia  5.4.3
Game Communication Engine
 全て クラス ネームスペース 関数 変数 型定義 列挙型 列挙型の値 ページ
common_ObjList.h
1 /*--------------------------------------------------------------------------------*
2  Copyright (C)Nintendo All rights reserved.
3 
4  These coded instructions, statements, and computer programs contain proprietary
5  information of Nintendo and/or its licensed developers and are protected by
6  national and international copyright laws. They may not be disclosed to third
7  parties or copied or duplicated in any form, in whole or in part, without the
8  prior written consent of Nintendo.
9 
10  The content herein is highly confidential and should be handled accordingly.
11  *--------------------------------------------------------------------------------*/
12 
13 
14 #pragma once
15 
16 #include <nn/pia/common/common_Definitions.h>
17 #include <nn/pia/common/common_OffsetList.h>
18 
19 
20 namespace nn
21 {
22 namespace pia
23 {
24 namespace common
25 {
26 
27 
28 /*!
29  @cond PRIVATE
30  @brief オブジェクトを格納するメモリを内部で管理する双方向リストです。
31 
32  @details リストを使用する前にSetBuffer()で利用するメモリ領域を指定する必要があります。
33  <br>
34  @param T 管理するオブジェクトの型。
35  */
36 template <typename T>
37 class ObjList : public nn::pia::common::ListBase
38 {
39 protected:
40  struct Node
41  {
42  public:
43  Node()
44  : m_Item()
45  {
46  }
47  Node(const Node& n)
48  : m_Item(n.m_Item)
49  {
50  }
51 
52  public:
53  ListNode m_Link;
54  T m_Item;
55 
56  private:
57  Node& operator=(const Node&);
58  };
59 
60  enum
61  {
62  NN_PIA_PRAGMA_PUSH_WARNINGS
63  NN_PIA_DISABLE_WARNING_CLANG_INVALID_OFFSETOF
64  c_LinkOffset = offsetof(Node, m_Link),
65  c_ItemOffset = offsetof(Node, m_Item)
66  NN_PIA_PRAGMA_POP_WARNINGS
67  };
68 
69 public:
70  /*!
71  @brief 要素オブジェクトの型です。
72  */
73  typedef T ValueType;
74 
75  enum
76  {
77  /*!
78  @brief 要素管理クラスのサイズです。
79 
80  @details c_NodeSize * (最大要素数) のサイズのバッファを使用します。
81  */
82  c_NodeSize = sizeof(Node)
83  };
84 
85 
86  /*!
87  @brief デフォルトコンストラクタです。
88  */
89  ObjList()
90  : ListBase(), m_FreeList(), m_pBuffer(NULL), m_LimitNum(0)
91  {
92  NN_PIA_PRAGMA_PUSH_WARNINGS
93  NN_PIA_DISABLE_WARNING_CLANG_INVALID_OFFSETOF
94  m_FreeList.InitOffset(offsetof(Node, m_Link));
95  NN_PIA_PRAGMA_POP_WARNINGS
96  }
97 
98 
99  /*!
100  @brief 必要なバッファのサイズを取得します。
101 
102  @return 必要なバッファのサイズ。
103  */
104  static uint32_t GetNeedBufferSize(uint32_t limitNum)
105  {
106  return limitNum * c_NodeSize;
107  }
108 
109 
110  /*!
111  @brief オブジェクトを格納するメモリを設定します。
112 
113  @details GetNeedBufferSize(limitNum) ( = limitNum * c_NodeSize ) バイトのメモリが必要です。
114  <br>
115  @param limitNum リストに格納する最大要素数。
116  @param pBuffer リストが使用するメモリのアドレス。
117  */
118  void SetBuffer(uint32_t limitNum, void* pBuffer)
119  {
120  if (limitNum > 0)
121  {
122  if (pBuffer != NULL)
123  {
124  m_pBuffer = reinterpret_cast<Node*>(pBuffer);
125  m_LimitNum = limitNum;
126  for (uint32_t i = 0; i < limitNum; ++i)
127  {
128  new (&m_pBuffer[i].m_Link) ListNode();
129  m_FreeList.PushBack(&m_pBuffer[i]);
130  }
131  }
132  else
133  {
134  PIA_ASSERTMSG(false, "pBuf is null");
135  }
136  }
137  else
138  {
139  PIA_ASSERTMSG(false, "limitNum[%d] must be larger than zero", limitNum);
140  }
141  }
142 
143 
144  /*!
145  @brief バッファが設定されているかどうかを取得します。
146 
147  @return バッファが設定されていればtrue。
148  */
149  bool IsBufferReady() const
150  {
151  return m_pBuffer != NULL;
152  }
153 
154 
155  /*!
156  @brief リストに格納できる最大の要素数を取得します。
157 
158  @return リストに格納できる最大の要素数。
159  */
160  uint32_t MaxSize() const
161  {
162  return m_LimitNum;
163  }
164 
165 
166  /*!
167  @brief リストの要素数が最大値に達しているかを取得します。
168 
169  @return リストの要素数が最大値に達していればtrue。
170  */
171  bool IsFull() const
172  {
173  return m_FreeList.IsEmpty();
174  }
175 
176 
177  /*!
178  @brief すべての要素を削除します。
179 
180  @details 保持している要素すべてに対してデストラクタを呼びます。
181  */
182  void Clear()
183  {
184  ListNode* pNode = Terminator()->Next();
185  while (pNode != Terminator())
186  {
187  ListNode* pN = pNode;
188  pNode = pNode->Next();
189  InitListNode(pN);
190  m_FreeList.PushFront(ListNodeToNode(pN));
191  }
192  Init();
193  }
194 
195 
196  /*!
197  @brief 要素を一つ作成し、リストの末尾に追加します。
198 
199  @details 保持できる要素数が上限に達していた場合は、release版ではNULLが返り、その他ではアサートにかかります。
200  <br>
201  @return 追加した要素。
202  */
203  T* BirthBack()
204  {
205  if (IsFull())
206  {
207  PIA_ASSERTMSG(false, "buffer full");
208  return NULL;
209  }
210  Node* pNode = m_FreeList.PopBack();
211  new (&pNode->m_Item) T();
212  PushBackNode(&(pNode->m_Link));
213  return &(pNode->m_Item);
214  }
215 
216 
217  /*!
218  @brief 要素を一つ作成し、リストの末尾に追加します。
219 
220  @details 保持できる要素数が上限に達していた場合は、NULLが返ります。
221  <br>
222  @return 追加した要素。
223  */
224  T* TryBirthBack()
225  {
226  if (IsFull())
227  {
228  return NULL;
229  }
230  Node* pNode = m_FreeList.PopBack();
231  new (&pNode->m_Item) T();
232  PushBackNode(&(pNode->m_Link));
233  return &(pNode->m_Item);
234  }
235 
236 
237  /*!
238  @brief 要素を一つ作成し、リストの先頭に追加します。
239 
240  @details 保持できる要素数が上限に達していた場合は、release版ではNULLが返り、その他ではアサートにかかります。
241  <br>
242  @return 追加した要素。
243  */
244  T* BirthFront()
245  {
246  if (IsFull())
247  {
248  PIA_ASSERTMSG(false, "buffer full");
249  return NULL;
250  }
251  Node* pNode = m_FreeList.PopBack();
252  new (&pNode->m_Item) T();
253  PushFrontNode(&(pNode->m_Link));
254  return &(pNode->m_Item);
255  }
256 
257 
258  /*!
259  @brief 要素を一つ作成し、リストの先頭に追加します。
260 
261  @details 保持できる要素数が上限に達していた場合は、NULLが返ります。
262  <br>
263  @return 追加した要素。
264  */
265  T* TryBirthFront()
266  {
267  if (IsFull())
268  {
269  return NULL;
270  }
271  Node* pNode = m_FreeList.PopBack();
272  new (&pNode->m_Item) T();
273  PushFrontNode(&(pNode->m_Link));
274  return &(pNode->m_Item);
275  }
276 
277 
278  /*!
279  @brief 要素を一つ作成し、指定した要素の前に追加します。
280 
281  @details 保持できる要素数が上限に達していた場合は、release版ではNULLが返り、その他ではアサートにかかります。
282  <br>
283  @param pBasis 基準となる要素。
284 
285  @return 追加した要素。
286  */
287  T* BirthBefore(const T* pBasis)
288  {
289  if (IsFull())
290  {
291  PIA_ASSERTMSG(false, "buffer full");
292  return NULL;
293  }
294  Node* pNode = m_FreeList.PopBack();
295  new (&pNode->m_Item) T();
296  InsertBeforeNode(&(ObjToNode(pBasis)->m_Link), &(pNode->m_Link));
297  return &(pNode->m_Item);
298  }
299 
300 
301  /*!
302  @brief 要素を一つ作成し、指定した要素の前に追加します。
303 
304  @details 保持できる要素数が上限に達していた場合は、NULLが返ります。
305  <br>
306  @param pBasis 基準となる要素。
307 
308  @return 追加した要素。
309  */
310  T* TryBirthBefore(const T* pBasis)
311  {
312  if (IsFull())
313  {
314  return NULL;
315  }
316  Node* pNode = m_FreeList.PopBack();
317  new (&pNode->m_Item) T();
318  InsertBeforeNode(&(ObjToNode(pBasis)->m_Link), &(pNode->m_Link));
319  return &(pNode->m_Item);
320  }
321 
322 
323  /*!
324  @brief 要素を一つ作成し、指定した要素の後ろに追加します。
325 
326  @details 保持できる要素数が上限に達していた場合は、release版ではNULLが返り、その他ではアサートにかかります。
327  <br>
328  @param pBasis 基準となる要素。
329 
330  @return 追加した要素。
331  */
332  T* BirthAfter(const T* pBasis)
333  {
334  if (IsFull())
335  {
336  PIA_ASSERTMSG(false, "buffer full");
337  return NULL;
338  }
339  Node* pNode = m_FreeList.PopBack();
340  new (&pNode->m_Item) T();
341  InsertAfterNode(&(ObjToNode(pBasis)->m_Link), &(pNode->m_Link));
342  return &(pNode->m_Item);
343  }
344 
345 
346  /*!
347  @brief 要素を一つ作成し、指定した要素の後ろに追加します。
348 
349  @details 保持できる要素数が上限に達していた場合は、NULLが返ります。
350  <br>
351  @param pBasis 基準となる要素。
352 
353  @return 追加した要素。
354  */
355  T* TryBirthAfter(const T* pBasis)
356  {
357  if (IsFull())
358  {
359  return NULL;
360  }
361  Node* pNode = m_FreeList.PopBack();
362  new (&pNode->m_Item) T();
363  InsertAfterNode(&(ObjToNode(pBasis)->m_Link), &(pNode->m_Link));
364  return &(pNode->m_Item);
365  }
366 
367 
368  /*!
369  @brief 指定した要素を削除します。
370 
371  @details リストに含まれていない要素を指定した場合の挙動は不定です。
372  <br>
373  @param pObj 削除する要素。
374  */
375  void Erase(T* pObj)
376  {
377  Node* pNode = ObjToNode(pObj);
378  pObj->~T();
379  EraseNode(&(pNode->m_Link));
380  m_FreeList.PushFront(pNode);
381  }
382 
383 
384  /*!
385  @brief 先頭の要素を取得します。
386 
387  @return 先頭の要素。
388  リストが空の場合はNULLを返します。
389  */
390  T* Front()
391  {
392  ListNode* pLink = FrontNode();
393  if (pLink == NULL)
394  {
395  return NULL;
396  }
397  return &(ListNodeToNode(pLink)->m_Item);
398  }
399 
400 
401  /*!
402  @brief 末尾の要素を取得します。
403 
404  @return 末尾の要素。
405  リストが空の場合はNULLを返します。
406  */
407  T* Back()
408  {
409  ListNode* pLink = BackNode();
410  if (pLink == NULL)
411  {
412  return NULL;
413  }
414  return &(ListNodeToNode(pLink)->m_Item);
415  }
416 
417 
418  /*!
419  @brief 指定した要素の前の要素を取得します。
420 
421  @param pObj 基準となる要素。
422  リストに含まれていない要素を指定した場合の挙動は不定です。
423 
424  @return 指定した要素の前の要素。
425  先頭の要素が指定された場合はNULLを返します。
426  */
427  T* Prev(const T* pObj)
428  {
429  ListNode* pPrevLink = ObjToNode(pObj)->m_Link.Prev();
430  if (pPrevLink == Terminator())
431  {
432  return NULL;
433  }
434  return &(ListNodeToNode(pPrevLink)->m_Item);
435  }
436 
437 
438  /*!
439  @brief 指定した要素の後ろの要素を取得します。
440 
441  @param pObj 基準となる要素。
442  リストに含まれていない要素を指定した場合の挙動は不定です。
443 
444  @return 指定した要素の後ろの要素。
445  末尾の要素が指定された場合はNULLを返します。
446  */
447  T* Next(const T* pObj)
448  {
449  ListNode* pNextLink = ObjToNode(pObj)->m_Link.Next();
450  if (pNextLink == Terminator())
451  {
452  return NULL;
453  }
454  return &(ListNodeToNode(pNextLink)->m_Item);
455  }
456 
457 
458  /*!
459  @brief 要素がリストに含まれているか調べます。
460 
461  @param pObj 調べたい要素。
462 
463  @return 含まれていれば true を返します。
464  */
465  bool IsInclude(const T* pObj) const
466  {
467  return IsIncludeNode(&(ObjToNode(pObj)->m_Link));
468  }
469 
470 
471  /*!
472  @brief ObjListのイテレータです。
473  */
474  class Iterator
475  {
476  friend class ObjList<T>;
477 
478  private:
479  Iterator(const ObjList<T>* pList, typename ObjList<T>::Node* pNode)
480  : m_pList(pList), m_pNode(pNode)
481  {
482  }
483 
484  public:
485  Iterator& operator++()
486  {
487  m_pNode = m_pList->ListNodeToNode(m_pNode->m_Link.Next());
488  return *this;
489  }
490 
491  bool operator==(const Iterator& x) const
492  {
493  return m_pNode == x.m_pNode;
494  }
495  bool operator!=(const Iterator& x) const
496  {
497  return m_pNode != x.m_pNode;
498  }
499 
500  T& operator*()
501  {
502  return m_pNode->m_Item;
503  }
504  T* operator->()
505  {
506  return &(m_pNode->m_Item);
507  }
508 
509  private:
510  const ObjList<T>* m_pList;
511  typename ObjList<T>::Node* m_pNode;
512  };
513 
514 
515  /*!
516  @brief ObjListのconst iteratorです。
517  */
518  class ConstIterator
519  {
520  friend class ObjList<T>;
521 
522  private:
523  ConstIterator(const ObjList<T>* pList, typename ObjList<T>::Node* pNode)
524  : m_pList(pList), m_pNode(pNode)
525  {
526  }
527 
528  public:
529  ConstIterator& operator++()
530  {
531  m_pNode = m_pList->ListNodeToNode(m_pNode->m_Link.Next());
532  return *this;
533  }
534 
535  bool operator==(const ConstIterator& x) const
536  {
537  return m_pNode == x.m_pNode;
538  }
539  bool operator!=(const ConstIterator& x) const
540  {
541  return m_pNode != x.m_pNode;
542  }
543 
544  const T& operator*() const
545  {
546  return m_pNode->m_Item;
547  }
548  const T* operator->() const
549  {
550  return &(m_pNode->m_Item);
551  }
552 
553  private:
554  const ObjList<T>* m_pList;
555  typename ObjList<T>::Node* m_pNode;
556  };
557 
558 
559  /*!
560  @brief ObjListのrobust iteratorです。
561 
562  @details イテレータが指し示す要素を削除してもイテレータを継続できます。
563  要素の追加やイテレータが指し示していない要素の削除をした場合はイテレータを継続できません。
564  */
565  class RobustIterator
566  {
567  friend class ObjList<T>;
568 
569  private:
570  RobustIterator(const ObjList<T>* pList, typename ObjList<T>::Node* pNode)
571  : m_pList(pList), m_pNode(pNode)
572  {
573  m_pNextLink = m_pNode->m_Link.Next();
574  }
575 
576  public:
577  RobustIterator& operator++()
578  {
579  m_pNode = m_pList->ListNodeToNode(m_pNextLink);
580  m_pNextLink = m_pNode->m_Link.Next();
581  return *this;
582  }
583 
584  bool operator==(const RobustIterator& x) const
585  {
586  return m_pNode == x.m_pNode;
587  }
588  bool operator!=(const RobustIterator& x) const
589  {
590  return m_pNode != x.m_pNode;
591  }
592 
593  T& operator*()
594  {
595  return m_pNode->m_Item;
596  }
597  T* operator->()
598  {
599  return &(m_pNode->m_Item);
600  }
601 
602  private:
603  const ObjList<T>* m_pList;
604  typename ObjList<T>::Node* m_pNode;
605  ListNode* m_pNextLink;
606  };
607 
608 
609  /*!
610  @brief 先頭の要素を指すIteratorを取得します。
611 
612  @return 先頭の要素を指すIterator。
613  */
614  Iterator Begin() const
615  {
616  return Iterator(this, ListNodeToNode(Terminator()->Next()));
617  }
618 
619 
620  /*!
621  @brief 末尾の要素の次を指すIteratorを取得します。
622 
623  @return 末尾の要素の次を指すIterator。
624  */
625  Iterator End() const
626  {
627  return Iterator(this, ListNodeToNode(Terminator()));
628  }
629 
630 
631  /*!
632  @brief 先頭の要素を指すConstIteratorを取得します。
633 
634  @return 先頭の要素を指すConstIterator。
635  */
636  ConstIterator ConstBegin() const
637  {
638  return ConstIterator(this, ListNodeToNode(Terminator()->Next()));
639  }
640 
641 
642  /*!
643  @brief 末尾の要素の次を指すConstIteratorを取得します。
644 
645  @return 末尾の要素の次を指すConstIterator。
646  */
647  ConstIterator ConstEnd() const
648  {
649  return ConstIterator(this, ListNodeToNode(Terminator()));
650  }
651 
652 
653  /*!
654  @brief 先頭の要素を指すRobustIteratorを取得します。
655 
656  @return 先頭の要素を指すRobustIterator。
657  */
658  RobustIterator RobustBegin() const
659  {
660  return RobustIterator(this, ListNodeToNode(Terminator()->Next()));
661  }
662 
663 
664  /*!
665  @brief 末尾の要素の次を指すRobustIteratorを取得します。
666 
667  @return 末尾の要素の次を指すRobustIterator。
668  */
669  RobustIterator RobustEnd() const
670  {
671  return RobustIterator(this, ListNodeToNode(Terminator()));
672  }
673 
674 private:
675  static Node* ObjToNode(const T* pObj)
676  {
677  return reinterpret_cast<Node*>(PtrUtil::addOffset(pObj, -c_ItemOffset));
678  }
679 
680  static Node* ListNodeToNode(const ListNode* pListNode)
681  {
682  return reinterpret_cast<Node*>(PtrUtil::addOffset(pListNode, -c_LinkOffset));
683  }
684 
685 
686 private:
687  OffsetList<Node> m_FreeList;
688  Node* m_pBuffer;
689  uint32_t m_LimitNum;
690 
691  ObjList(const ObjList&);
692  ObjList& operator=(const ObjList&);
693 };
694 //! @endcond
695 }
696 }
697 } // end of namespace nn::pia::common