LiquidFun
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
b2IntrusiveList.h
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 
22 
23 // Whether to enable b2IntrusiveList::ValidateList().
24 // Be careful when enabling this since this changes the size of
25 // b2IntrusiveListNode so make sure *all* projects that include Box2D.h
26 // also define this value in the same way to avoid data corruption.
27 #ifndef B2_INTRUSIVE_LIST_VALIDATE
28 #define B2_INTRUSIVE_LIST_VALIDATE 0
29 #endif // B2_INTRUSIVE_LIST_VALIDATE
30 
65 {
66 public:
69  {
70  Initialize();
71 #if B2_INTRUSIVE_LIST_VALIDATE
72  m_magic = k_magic;
73 #endif // B2_INTRUSIVE_LIST_VALIDATE
74  }
75 
78  {
79  Remove();
80 #if B2_INTRUSIVE_LIST_VALIDATE
81  m_magic = 0;
82 #endif // B2_INTRUSIVE_LIST_VALIDATE
83  }
84 
86  void InsertAfter(b2IntrusiveListNode* const node)
87  {
88  b2Assert(!node->InList());
89  node->m_next = m_next;
90  node->m_prev = this;
91  m_next->m_prev = node;
92  m_next = node;
93  }
94 
97  {
98  b2Assert(!node->InList());
99  node->m_next = this;
100  node->m_prev = m_prev;
101  m_prev->m_next = node;
102  m_prev = node;
103  }
104 
107  {
108  return this;
109  }
110 
113  {
114  m_prev->m_next = m_next;
115  m_next->m_prev = m_prev;
116  Initialize();
117  return this;
118  }
119 
121  bool IsEmpty() const
122  {
123  return GetNext() == this;
124  }
125 
127  bool InList() const
128  {
129  return !IsEmpty();
130  }
131 
133  uint32 GetLength() const
134  {
135  uint32 length = 0;
136  const b2IntrusiveListNode * const terminator = GetTerminator();
137  for (const b2IntrusiveListNode* node = GetNext();
138  node != terminator; node = node->GetNext())
139  {
140  length++;
141  }
142  return length;
143  }
144 
147  {
148  return m_next;
149  }
150 
153  {
154  return m_prev;
155  }
156 
159  bool ValidateList() const
160  {
161 #if B2_INTRUSIVE_LIST_VALIDATE
162  if (m_magic != k_magic) return false;
163  const b2IntrusiveListNode * const terminator = GetTerminator();
164  for (b2IntrusiveListNode *node = GetNext(); node != terminator;
165  node = node->GetNext()) {
166  if (node->m_magic != k_magic) return false;
167  }
168 #endif // B2_INTRUSIVE_LIST_VALIDATE
169  return true;
170  }
171 
173  bool FindNodeInList(b2IntrusiveListNode* const nodeToFind) const
174  {
175  const b2IntrusiveListNode * const terminator = GetTerminator();
176  for (b2IntrusiveListNode *node = GetNext(); node != terminator;
177  node = node->GetNext())
178  {
179  if (nodeToFind == node) return true;
180  }
181  return false;
182  }
183 
184 private:
186  void Initialize()
187  {
188  m_next = this;
189  m_prev = this;
190  }
191 
192 private:
193 #if B2_INTRUSIVE_LIST_VALIDATE
194  uint32 m_magic;
195 #endif // B2_INTRUSIVE_LIST_VALIDATE
196  b2IntrusiveListNode *m_prev;
199  b2IntrusiveListNode *m_next;
200 
201 private:
202 #if B2_INTRUSIVE_LIST_VALIDATE
203  static const uint32 k_magic = 0x7157ac01;
204 #endif // B2_INTRUSIVE_LIST_VALIDATE
205 };
206 
210 #define B2_INTRUSIVE_LIST_GET_NODE(NodeMemberName) \
211  b2IntrusiveListNode* GetListNode() { return &NodeMemberName; } \
212  const b2IntrusiveListNode* GetListNode() const { return &NodeMemberName; }
213 
217 #define B2_INTRUSIVE_LIST_NODE_GET_CLASS_ACCESSOR( \
218  Class, NodeMemberName, FunctionName) \
219  static Class* FunctionName(b2IntrusiveListNode *node) \
220  { \
221  Class *cls = NULL; \
222  /* This effectively performs offsetof(Class, NodeMemberName) */ \
223  /* which ends up in the undefined behavior realm of C++ but in */ \
224  /* practice this works with most compilers. */ \
225  return reinterpret_cast<Class*>((uint8*)(node) - \
226  (uint8*)(&cls->NodeMemberName)); \
227  } \
228  \
229  static const Class* FunctionName(const b2IntrusiveListNode *node) \
230  { \
231  return FunctionName(const_cast<b2IntrusiveListNode*>(node)); \
232  }
233 
237 #define B2_INTRUSIVE_LIST_NODE_GET_CLASS(Class, NodeMemberName) \
238  B2_INTRUSIVE_LIST_NODE_GET_CLASS_ACCESSOR(Class, NodeMemberName, \
239  GetInstanceFromListNode)
240 
271 template<typename T>
273 {
274 public:
277 
279  void InsertAfter(T* const obj)
280  {
281  b2Assert(obj);
282  GetListNode()->InsertAfter(obj->GetListNode());
283  }
284 
286  void InsertBefore(T* const obj)
287  {
288  b2Assert(obj);
289  GetListNode()->InsertBefore(obj->GetListNode());
290  }
291 
294  T* GetNext() const
295  {
296  return GetInstanceFromListNode(GetListNode()->GetNext());
297  }
298 
301  T* GetPrevious() const
302  {
303  return GetInstanceFromListNode(GetListNode()->GetPrevious());
304  }
305 
309  T* GetTerminator() const
310  {
311  return (T*)GetListNode();
312  }
313 
315  T* Remove()
316  {
317  GetListNode()->Remove();
318  return GetInstanceFromListNode(GetListNode());
319  }
320 
322  bool InList() const
323  {
324  return GetListNode()->InList();
325  }
326 
327  // Determine whether this list is empty.
328  bool IsEmpty() const
329  {
330  return GetListNode()->IsEmpty();
331  }
332 
334  uint32 GetLength() const
335  {
336  return GetListNode()->GetLength();
337  }
338 
339  B2_INTRUSIVE_LIST_GET_NODE(m_node);
340 
341 private:
342  // Node within an intrusive list.
343  b2IntrusiveListNode m_node;
344 
345 public:
348  {
349  b2Assert(node);
350  // Calculate the pointer to T from the offset.
351  return (T*)((uint8*)node - GetNodeOffset(node));
352  }
353 
354 private:
355  // Get the offset of m_node within this class.
356  static int32 GetNodeOffset(b2IntrusiveListNode* const node)
357  {
358  b2Assert(node);
359  // Perform some type punning to calculate the offset of m_node in T.
360  // WARNING: This could result in undefined behavior with some C++
361  // compilers.
362  T* obj = (T*)node;
363  int32 nodeOffset = (int32)((uint8*)&obj->m_node - (uint8*)obj);
364  return nodeOffset;
365  }
366 };
367 
368 #endif // B2_INTRUSIVE_LIST
369 
T * GetPrevious() const
Definition: b2IntrusiveList.h:301
static T * GetInstanceFromListNode(b2IntrusiveListNode *const node)
Get a pointer to the instance of T that contains "node".
Definition: b2IntrusiveList.h:347
bool ValidateList() const
Definition: b2IntrusiveList.h:159
uint32 GetLength() const
Calculate the length of the list.
Definition: b2IntrusiveList.h:334
b2IntrusiveListNode()
Initialize the node.
Definition: b2IntrusiveList.h:68
b2IntrusiveListNode * Remove()
Remove this node from the list it's currently in.
Definition: b2IntrusiveList.h:112
bool InList() const
Determine whether this object is in a list.
Definition: b2IntrusiveList.h:322
Definition: b2IntrusiveList.h:64
b2IntrusiveListNode * GetPrevious() const
Get the previous node in the list.
Definition: b2IntrusiveList.h:152
T * GetNext() const
Definition: b2IntrusiveList.h:294
uint32 GetLength() const
Calculate the length of the list.
Definition: b2IntrusiveList.h:133
void InsertAfter(T *const obj)
Insert this object after the specified object.
Definition: b2IntrusiveList.h:279
Definition: b2IntrusiveList.h:272
bool FindNodeInList(b2IntrusiveListNode *const nodeToFind) const
Determine whether the specified node is present in this list.
Definition: b2IntrusiveList.h:173
T * Remove()
Remove this object from the list it's currently in.
Definition: b2IntrusiveList.h:315
b2IntrusiveListNode * GetNext() const
Get the next node in the list.
Definition: b2IntrusiveList.h:146
void InsertBefore(T *const obj)
Insert this object before the specified object.
Definition: b2IntrusiveList.h:286
bool InList() const
Determine whether this node is in a list or the list contains nodes.
Definition: b2IntrusiveList.h:127
bool IsEmpty() const
Determine whether this list is empty or the node isn't in a list.
Definition: b2IntrusiveList.h:121
void InsertBefore(b2IntrusiveListNode *const node)
Insert this node before the specified node.
Definition: b2IntrusiveList.h:96
const b2IntrusiveListNode * GetTerminator() const
Get the terminator of the list.
Definition: b2IntrusiveList.h:106
~b2IntrusiveListNode()
If the node is in a list, remove it from the list.
Definition: b2IntrusiveList.h:77
T * GetTerminator() const
Definition: b2IntrusiveList.h:309
void InsertAfter(b2IntrusiveListNode *const node)
Insert this node after the specified node.
Definition: b2IntrusiveList.h:86