eathread_list.h 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // Copyright (c) Electronic Arts Inc. All rights reserved.
  3. ///////////////////////////////////////////////////////////////////////////////
  4. /////////////////////////////////////////////////////////////////////////////
  5. // This is a small templated list implementation which suffices for our
  6. // purposes but is not optimal. It is present in order to avoid dependencies
  7. // on external libraries.
  8. /////////////////////////////////////////////////////////////////////////////
  9. #ifndef EATHREAD_EATHREAD_LIST_H
  10. #define EATHREAD_EATHREAD_LIST_H
  11. #include <eathread/internal/config.h>
  12. #include <eathread/eathread.h>
  13. #include <stddef.h> // size_t, etc.
  14. #include <new>
  15. #if defined(EA_PRAGMA_ONCE_SUPPORTED)
  16. #pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result.
  17. #endif
  18. namespace EA
  19. {
  20. namespace Thread
  21. {
  22. namespace details
  23. {
  24. /// Default allocator implementation used by the simple_list class
  25. template<typename T>
  26. struct ListDefaultAllocatorImpl
  27. {
  28. template<typename OT>
  29. struct rebind { typedef ListDefaultAllocatorImpl<OT> other; };
  30. T* construct()
  31. {
  32. Allocator* pAllocator = GetAllocator();
  33. if(pAllocator)
  34. return new(pAllocator->Alloc(sizeof(T))) T;
  35. else
  36. return new T;
  37. }
  38. void destroy(T* obj)
  39. {
  40. Allocator* pAllocator = GetAllocator();
  41. if(pAllocator)
  42. {
  43. obj->~T();
  44. pAllocator->Free(obj);
  45. }
  46. else
  47. delete obj;
  48. }
  49. };
  50. }
  51. /// Simple version of an STL bidirectional list.
  52. /// Implemented to avoid dependency on container implementations.
  53. ///
  54. /// This implementation has some non-stl standard methods like find.
  55. ///
  56. template<typename T, class Allocator = details::ListDefaultAllocatorImpl<T> >
  57. class simple_list
  58. {
  59. simple_list(const simple_list&);
  60. simple_list& operator=(const simple_list&);
  61. protected:
  62. struct list_node
  63. {
  64. T mValue;
  65. list_node* mpPrev;
  66. list_node* mpNext;
  67. };
  68. typedef list_node node_t;
  69. typedef typename Allocator::template rebind<list_node>::other allocator_t;
  70. allocator_t mAllocator;
  71. node_t* mpNodeHead;
  72. node_t* mpNodeTail;
  73. size_t mnSize;
  74. public:
  75. typedef T value_type; //< list value type
  76. typedef const T const_value_type; //< constant list value type
  77. typedef const T& const_value_ref_type; //< constant reference list value type
  78. struct const_iterator;
  79. struct iterator;
  80. friend struct const_iterator;
  81. friend struct iterator;
  82. struct const_iterator
  83. {
  84. friend class simple_list<T>;
  85. const_iterator()
  86. : mpNode(NULL)
  87. { }
  88. const_iterator(const const_iterator& rhs)
  89. : mpNode(rhs.mpNode)
  90. { }
  91. const_iterator& operator=(const const_iterator& rhs)
  92. {
  93. mpNode = rhs.mpNode;
  94. return *this;
  95. }
  96. const T& operator*() const
  97. { return mpNode->mValue; }
  98. const T* operator->() const
  99. { return &**this; }
  100. bool operator==(const const_iterator& rhs) const
  101. { return rhs.mpNode == mpNode; }
  102. bool operator!=(const const_iterator& rhs) const
  103. { return rhs.mpNode != mpNode; }
  104. const_iterator& operator++()
  105. {
  106. mpNode = mpNode->mpNext;
  107. return *this;
  108. }
  109. protected:
  110. const node_t* mpNode;
  111. protected:
  112. const_iterator(node_t* pNode)
  113. : mpNode(pNode)
  114. { }
  115. const_iterator& operator=(const node_t* pNode)
  116. {
  117. mpNode = pNode;
  118. return *this;
  119. }
  120. }; // const_iterator
  121. struct iterator : public const_iterator
  122. {
  123. friend class simple_list<T>;
  124. iterator()
  125. : const_iterator(){ }
  126. iterator(const const_iterator& rhs)
  127. : const_iterator(rhs)
  128. { }
  129. iterator& operator=(const const_iterator& rhs)
  130. {
  131. *static_cast<const_iterator*>(this)= rhs;
  132. return *this;
  133. }
  134. T& operator*() const
  135. { return const_cast<T&>(**static_cast<const const_iterator*>(this)); }
  136. T& operator->() const
  137. { return const_cast<T*>(&**static_cast<const const_iterator*>(this)); }
  138. iterator& operator++()
  139. {
  140. ++(*static_cast<const_iterator*>(this));
  141. return *this;
  142. }
  143. protected:
  144. iterator(node_t* pNode)
  145. : const_iterator(pNode)
  146. { }
  147. iterator& operator=(node_t* pNode)
  148. {
  149. const_cast<node_t*>(*this) = pNode;
  150. return *this;
  151. }
  152. }; // iterator
  153. simple_list()
  154. : mnSize(0)
  155. {
  156. mpNodeHead = mAllocator.construct();
  157. mpNodeTail = mAllocator.construct();
  158. mpNodeHead->mpNext = mpNodeTail;
  159. mpNodeHead->mpPrev = mpNodeTail;
  160. mpNodeTail->mpNext = mpNodeHead;
  161. mpNodeTail->mpPrev = mpNodeHead;
  162. }
  163. ~simple_list()
  164. {
  165. clear();
  166. mAllocator.destroy(mpNodeHead);
  167. mAllocator.destroy(mpNodeTail);
  168. }
  169. bool empty() const
  170. { return mpNodeHead->mpNext == mpNodeTail; }
  171. void push_back(const T& value)
  172. {
  173. node_t* const pNode = mAllocator.construct();
  174. pNode->mValue = value;
  175. pNode->mpPrev = mpNodeTail->mpPrev;
  176. pNode->mpNext = mpNodeTail;
  177. pNode->mpPrev->mpNext = pNode;
  178. mpNodeTail->mpPrev = pNode;
  179. ++mnSize;
  180. }
  181. void push_front(const T& value)
  182. {
  183. node_t* const pNode = mAllocator.construct();
  184. pNode->mValue = value;
  185. pNode->mpPrev = mpNodeHead;
  186. pNode->mpNext = mpNodeHead->mpNext;
  187. mpNodeHead->mpNext = pNode;
  188. ++mnSize;
  189. }
  190. void pop_front()
  191. {
  192. if(!empty())
  193. {
  194. node_t* const pNode = mpNodeHead->mpNext;
  195. mpNodeHead->mpNext = pNode->mpNext;
  196. pNode->mpNext->mpPrev = mpNodeHead;
  197. mAllocator.destroy(pNode);
  198. --mnSize;
  199. }
  200. }
  201. size_t size() const
  202. { return mnSize; }
  203. iterator erase(iterator& iter)
  204. {
  205. if(!empty())
  206. {
  207. node_t* const pNext = iter.mpNode->mpNext;
  208. iter.mpNode->mpNext->mpPrev = iter.mpNode->mpPrev;
  209. iter.mpNode->mpPrev->mpNext = iter.mpNode->mpNext;
  210. --mnSize;
  211. mAllocator.destroy(const_cast<node_t*>(iter.mpNode));
  212. return pNext;
  213. }
  214. return end();
  215. }
  216. void clear()
  217. {
  218. if(!empty())
  219. {
  220. node_t* pNode = mpNodeHead->mpNext;
  221. while(pNode != mpNodeTail)
  222. {
  223. node_t* const pNext = pNode->mpNext;
  224. pNode->mpNext->mpPrev = pNode->mpPrev;
  225. pNode->mpPrev->mpNext = pNext;
  226. mAllocator.destroy(pNode);
  227. pNode = pNext;
  228. }
  229. mnSize = 0;
  230. }
  231. }
  232. T& front() const
  233. { return mpNodeHead->mpNext->mValue; }
  234. const const_iterator begin() const
  235. { return mpNodeHead->mpNext; }
  236. const const_iterator end() const
  237. { return mpNodeTail; }
  238. /// returns end()if not found
  239. iterator find(const T& element)
  240. {
  241. iterator iter = begin();
  242. while((iter != end()) && !(element == *iter))
  243. ++iter;
  244. return iter;
  245. }
  246. }; // simple_list
  247. } // namespace Thread
  248. } // namespace EA
  249. #endif // EATHREAD_EATHREAD_LIST_H