b2IntrusiveList.h 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  1. /*
  2. * Copyright (c) 2014 Google, Inc.
  3. *
  4. * This software is provided 'as-is', without any express or implied
  5. * warranty. In no event will the authors be held liable for any damages
  6. * arising from the use of this software.
  7. * Permission is granted to anyone to use this software for any purpose,
  8. * including commercial applications, and to alter it and redistribute it
  9. * freely, subject to the following restrictions:
  10. * 1. The origin of this software must not be misrepresented; you must not
  11. * claim that you wrote the original software. If you use this software
  12. * in a product, an acknowledgment in the product documentation would be
  13. * appreciated but is not required.
  14. * 2. Altered source versions must be plainly marked as such, and must not be
  15. * misrepresented as being the original software.
  16. * 3. This notice may not be removed or altered from any source distribution.
  17. */
  18. #ifndef B2_INTRUSIVE_LIST
  19. #define B2_INTRUSIVE_LIST
  20. #include <Box2D/Common/b2Settings.h>
  21. // Whether to enable b2IntrusiveList::ValidateList().
  22. // Be careful when enabling this since this changes the size of
  23. // b2IntrusiveListNode so make sure *all* projects that include Box2D.h
  24. // also define this value in the same way to avoid data corruption.
  25. #ifndef B2_INTRUSIVE_LIST_VALIDATE
  26. #define B2_INTRUSIVE_LIST_VALIDATE 0
  27. #endif // B2_INTRUSIVE_LIST_VALIDATE
  28. /// b2IntrusiveListNode is used to implement an intrusive doubly-linked
  29. /// list.
  30. ///
  31. /// For example:
  32. ///
  33. /// class MyClass {
  34. /// public:
  35. /// MyClass(const char *msg) : m_msg(msg) {}
  36. /// const char* GetMessage() const { return m_msg; }
  37. /// B2_INTRUSIVE_LIST_GET_NODE(m_node);
  38. /// B2_INTRUSIVE_LIST_NODE_GET_CLASS(MyClass, m_node);
  39. /// private:
  40. /// b2IntrusiveListNode m_node;
  41. /// const char *m_msg;
  42. /// };
  43. ///
  44. /// int main(int argc, char *argv[]) {
  45. /// b2IntrusiveListNode list; // NOTE: type is NOT MyClass
  46. /// MyClass a("this");
  47. /// MyClass b("is");
  48. /// MyClass c("a");
  49. /// MyClass d("test");
  50. /// list.InsertBefore(a.GetListNode());
  51. /// list.InsertBefore(b.GetListNode());
  52. /// list.InsertBefore(c.GetListNode());
  53. /// list.InsertBefore(d.GetListNode());
  54. /// for (b2IntrusiveListNode* node = list.GetNext();
  55. /// node != list.GetTerminator(); node = node->GetNext()) {
  56. /// MyClass *cls = MyClass::GetInstanceFromListNode(node);
  57. /// printf("%s\n", cls->GetMessage());
  58. /// }
  59. /// return 0;
  60. /// }
  61. class b2IntrusiveListNode
  62. {
  63. public:
  64. /// Initialize the node.
  65. b2IntrusiveListNode()
  66. {
  67. Initialize();
  68. #if B2_INTRUSIVE_LIST_VALIDATE
  69. m_magic = k_magic;
  70. #endif // B2_INTRUSIVE_LIST_VALIDATE
  71. }
  72. /// If the node is in a list, remove it from the list.
  73. ~b2IntrusiveListNode()
  74. {
  75. Remove();
  76. #if B2_INTRUSIVE_LIST_VALIDATE
  77. m_magic = 0;
  78. #endif // B2_INTRUSIVE_LIST_VALIDATE
  79. }
  80. /// Insert this node after the specified node.
  81. void InsertAfter(b2IntrusiveListNode* const node)
  82. {
  83. b2Assert(!node->InList());
  84. node->m_next = m_next;
  85. node->m_prev = this;
  86. m_next->m_prev = node;
  87. m_next = node;
  88. }
  89. /// Insert this node before the specified node.
  90. void InsertBefore(b2IntrusiveListNode* const node)
  91. {
  92. b2Assert(!node->InList());
  93. node->m_next = this;
  94. node->m_prev = m_prev;
  95. m_prev->m_next = node;
  96. m_prev = node;
  97. }
  98. /// Get the terminator of the list.
  99. const b2IntrusiveListNode* GetTerminator() const
  100. {
  101. return this;
  102. }
  103. /// Remove this node from the list it's currently in.
  104. b2IntrusiveListNode* Remove()
  105. {
  106. m_prev->m_next = m_next;
  107. m_next->m_prev = m_prev;
  108. Initialize();
  109. return this;
  110. }
  111. /// Determine whether this list is empty or the node isn't in a list.
  112. bool IsEmpty() const
  113. {
  114. return GetNext() == this;
  115. }
  116. /// Determine whether this node is in a list or the list contains nodes.
  117. bool InList() const
  118. {
  119. return !IsEmpty();
  120. }
  121. /// Calculate the length of the list.
  122. uint32 GetLength() const
  123. {
  124. uint32 length = 0;
  125. const b2IntrusiveListNode * const terminator = GetTerminator();
  126. for (const b2IntrusiveListNode* node = GetNext();
  127. node != terminator; node = node->GetNext())
  128. {
  129. length++;
  130. }
  131. return length;
  132. }
  133. /// Get the next node in the list.
  134. b2IntrusiveListNode* GetNext() const
  135. {
  136. return m_next;
  137. }
  138. /// Get the previous node in the list.
  139. b2IntrusiveListNode* GetPrevious() const
  140. {
  141. return m_prev;
  142. }
  143. /// If B2_INTRUSIVE_LIST_VALIDATE is 1 perform a very rough validation
  144. /// of all nodes in the list.
  145. bool ValidateList() const
  146. {
  147. #if B2_INTRUSIVE_LIST_VALIDATE
  148. if (m_magic != k_magic) return false;
  149. const b2IntrusiveListNode * const terminator = GetTerminator();
  150. for (b2IntrusiveListNode *node = GetNext(); node != terminator;
  151. node = node->GetNext()) {
  152. if (node->m_magic != k_magic) return false;
  153. }
  154. #endif // B2_INTRUSIVE_LIST_VALIDATE
  155. return true;
  156. }
  157. /// Determine whether the specified node is present in this list.
  158. bool FindNodeInList(b2IntrusiveListNode* const nodeToFind) const
  159. {
  160. const b2IntrusiveListNode * const terminator = GetTerminator();
  161. for (b2IntrusiveListNode *node = GetNext(); node != terminator;
  162. node = node->GetNext())
  163. {
  164. if (nodeToFind == node) return true;
  165. }
  166. return false;
  167. }
  168. private:
  169. /// Initialize the list node.
  170. void Initialize()
  171. {
  172. m_next = this;
  173. m_prev = this;
  174. }
  175. private:
  176. #if B2_INTRUSIVE_LIST_VALIDATE
  177. uint32 m_magic;
  178. #endif // B2_INTRUSIVE_LIST_VALIDATE
  179. /// The next node in the list.
  180. b2IntrusiveListNode *m_prev;
  181. /// The previous node in the list.
  182. b2IntrusiveListNode *m_next;
  183. private:
  184. #if B2_INTRUSIVE_LIST_VALIDATE
  185. static const uint32 k_magic = 0x7157ac01;
  186. #endif // B2_INTRUSIVE_LIST_VALIDATE
  187. };
  188. /// Declares the member function GetListNode() of Class to retrieve a pointer
  189. /// to NodeMemberName.
  190. /// See #B2_INTRUSIVE_LIST_NODE_GET_CLASS_ACCESSOR()
  191. #define B2_INTRUSIVE_LIST_GET_NODE(NodeMemberName) \
  192. b2IntrusiveListNode* GetListNode() { return &NodeMemberName; } \
  193. const b2IntrusiveListNode* GetListNode() const { return &NodeMemberName; }
  194. /// Declares the member function FunctionName of Class to retrieve a pointer
  195. /// to a Class instance from a list node pointer. NodeMemberName references
  196. /// the name of the b2IntrusiveListNode member of Class.
  197. #define B2_INTRUSIVE_LIST_NODE_GET_CLASS_ACCESSOR( \
  198. Class, NodeMemberName, FunctionName) \
  199. static Class* FunctionName(b2IntrusiveListNode *node) \
  200. { \
  201. Class *cls = NULL; \
  202. /* This effectively performs offsetof(Class, NodeMemberName) */ \
  203. /* which ends up in the undefined behavior realm of C++ but in */ \
  204. /* practice this works with most compilers. */ \
  205. return reinterpret_cast<Class*>((uint8*)(node) - \
  206. (uint8*)(&cls->NodeMemberName)); \
  207. } \
  208. \
  209. static const Class* FunctionName(const b2IntrusiveListNode *node) \
  210. { \
  211. return FunctionName(const_cast<b2IntrusiveListNode*>(node)); \
  212. }
  213. /// Declares the member function GetInstanceFromListNode() of Class to retrieve
  214. /// a pointer to a Class instance from a list node pointer. NodeMemberName
  215. /// reference the name of the b2IntrusiveListNode member of Class.
  216. #define B2_INTRUSIVE_LIST_NODE_GET_CLASS(Class, NodeMemberName) \
  217. B2_INTRUSIVE_LIST_NODE_GET_CLASS_ACCESSOR(Class, NodeMemberName, \
  218. GetInstanceFromListNode)
  219. /// b2TypedIntrusiveListNode which supports inserting an object into a single
  220. /// doubly linked list. For objects that need to be inserted in multiple
  221. /// doubly linked lists, use b2IntrusiveListNode.
  222. ///
  223. /// For example:
  224. ///
  225. /// class IntegerItem : public b2TypedIntrusiveListNode<IntegerItem>
  226. /// {
  227. /// public:
  228. /// IntegerItem(int32 value) : m_value(value) { }
  229. /// ~IntegerItem() { }
  230. /// int32 GetValue() const { return m_value; }
  231. /// private:
  232. /// int32 m_value;
  233. /// };
  234. ///
  235. /// int main(int argc, const char *arvg[]) {
  236. /// b2TypedIntrusiveListNode<IntegerItem> list;
  237. /// IntegerItem a(1);
  238. /// IntegerItem b(2);
  239. /// IntegerItem c(3);
  240. /// list.InsertBefore(&a);
  241. /// list.InsertBefore(&b);
  242. /// list.InsertBefore(&c);
  243. /// for (IntegerItem* item = list.GetNext();
  244. /// item != list.GetTerminator(); item = item->GetNext())
  245. /// {
  246. /// printf("%d\n", item->GetValue());
  247. /// }
  248. /// }
  249. template<typename T>
  250. class b2TypedIntrusiveListNode
  251. {
  252. public:
  253. b2TypedIntrusiveListNode() { }
  254. ~b2TypedIntrusiveListNode() { }
  255. /// Insert this object after the specified object.
  256. void InsertAfter(T* const obj)
  257. {
  258. b2Assert(obj);
  259. GetListNode()->InsertAfter(obj->GetListNode());
  260. }
  261. /// Insert this object before the specified object.
  262. void InsertBefore(T* const obj)
  263. {
  264. b2Assert(obj);
  265. GetListNode()->InsertBefore(obj->GetListNode());
  266. }
  267. /// Get the next object in the list.
  268. /// Check against GetTerminator() before deferencing the object.
  269. T* GetNext() const
  270. {
  271. return GetInstanceFromListNode(GetListNode()->GetNext());
  272. }
  273. /// Get the previous object in the list.
  274. /// Check against GetTerminator() before deferencing the object.
  275. T* GetPrevious() const
  276. {
  277. return GetInstanceFromListNode(GetListNode()->GetPrevious());
  278. }
  279. /// Get the terminator of the list.
  280. /// This should not be dereferenced as it is a pointer to
  281. /// b2TypedIntrusiveListNode<T> *not* T.
  282. T* GetTerminator() const
  283. {
  284. return (T*)GetListNode();
  285. }
  286. /// Remove this object from the list it's currently in.
  287. T* Remove()
  288. {
  289. GetListNode()->Remove();
  290. return GetInstanceFromListNode(GetListNode());
  291. }
  292. /// Determine whether this object is in a list.
  293. bool InList() const
  294. {
  295. return GetListNode()->InList();
  296. }
  297. // Determine whether this list is empty.
  298. bool IsEmpty() const
  299. {
  300. return GetListNode()->IsEmpty();
  301. }
  302. /// Calculate the length of the list.
  303. uint32 GetLength() const
  304. {
  305. return GetListNode()->GetLength();
  306. }
  307. B2_INTRUSIVE_LIST_GET_NODE(m_node);
  308. private:
  309. // Node within an intrusive list.
  310. b2IntrusiveListNode m_node;
  311. public:
  312. /// Get a pointer to the instance of T that contains "node".
  313. static T* GetInstanceFromListNode(b2IntrusiveListNode* const node)
  314. {
  315. b2Assert(node);
  316. // Calculate the pointer to T from the offset.
  317. return (T*)((uint8*)node - GetNodeOffset(node));
  318. }
  319. private:
  320. // Get the offset of m_node within this class.
  321. static int32 GetNodeOffset(b2IntrusiveListNode* const node)
  322. {
  323. b2Assert(node);
  324. // Perform some type punning to calculate the offset of m_node in T.
  325. // WARNING: This could result in undefined behavior with some C++
  326. // compilers.
  327. T* obj = (T*)node;
  328. int32 nodeOffset = (int32)((uint8*)&obj->m_node - (uint8*)obj);
  329. return nodeOffset;
  330. }
  331. };
  332. #endif // B2_INTRUSIVE_LIST