Newton Dynamics  4.00
ndList.h
1 /* Copyright (c) <2003-2022> <Julio Jerez, Newton Game Dynamics>
2 *
3 * This software is provided 'as-is', without any express or implied
4 * warranty. In no event will the authors be held liable for any damages
5 * arising from the use of this software.
6 *
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 *
11 * 1. The origin of this software must not be misrepresented; you must not
12 * claim that you wrote the original software. If you use this software
13 * in a product, an acknowledgment in the product documentation would be
14 * appreciated but is not required.
15 *
16 * 2. Altered source versions must be plainly marked as such, and must not be
17 * misrepresented as being the original software.
18 *
19 * 3. This notice may not be removed or altered from any source distribution.
20 */
21 
22 #ifndef __ND_LIST_H__
23 #define __ND_LIST_H__
24 
25 #include "ndCoreStdafx.h"
26 #include "ndTypes.h"
27 #include "ndMemory.h"
28 #include "ndClassAlloc.h"
29 #include "ndContainersAlloc.h"
30 
31 template<class T, class allocator = ndContainersAlloc<T> >
32 class ndList: public ndClassAlloc
33 {
34  public:
35  class ndNode: public allocator
36  {
37  ndNode (ndNode* const prev, ndNode* const next)
38  :allocator()
39  ,m_info ()
40  ,m_next(next)
41  ,m_prev(prev)
42  {
43  if (m_prev)
44  {
45  m_prev->m_next = this;
46  }
47  if (m_next)
48  {
49  m_next->m_prev = this;
50  }
51  }
52 
53  ndNode (const T &info, ndNode* const prev, ndNode* const next)
54  :allocator()
55  ,m_info (info)
56  ,m_next(next)
57  ,m_prev(prev)
58  {
59  if (m_prev)
60  {
61  m_prev->m_next = this;
62  }
63  if (m_next)
64  {
65  m_next->m_prev = this;
66  }
67  }
68 
69  ~ndNode()
70  {
71  }
72 
73  void Unlink ()
74  {
75  if (m_prev)
76  {
77  m_prev->m_next = m_next;
78  }
79  if (m_next)
80  {
81  m_next->m_prev = m_prev;
82  }
83  m_prev = nullptr;
84  m_next = nullptr;
85  }
86 
87  void AddLast(ndNode* const node)
88  {
89  m_next = node;
90  node->m_prev = this;
91  }
92 
93  void AddFirst(ndNode* const node)
94  {
95  m_prev = node;
96  node->m_next = this;
97  }
98 
99  public:
100  T& GetInfo()
101  {
102  return m_info;
103  }
104 
105  ndNode *GetNext() const
106  {
107  return m_next;
108  }
109 
110  ndNode *GetPrev() const
111  {
112  return m_prev;
113  }
114 
115  private:
116  T m_info;
117  ndNode *m_next;
118  ndNode *m_prev;
119  friend class ndList<T, allocator>;
120  };
121 
122  class Iterator
123  {
124  public:
125  Iterator (const ndList<T, allocator> &me)
126  {
127  m_ptr = nullptr;
128  m_list = (ndList *)&me;
129  }
130 
131  ~Iterator ()
132  {
133  }
134 
135  operator ndInt32() const
136  {
137  return m_ptr != nullptr;
138  }
139 
140  bool operator== (const Iterator &target) const
141  {
142  return (m_ptr == target.m_ptr) && (m_list == target.m_list);
143  }
144 
145  void Begin()
146  {
147  m_ptr = m_list->GetFirst();
148  }
149 
150  void End()
151  {
152  m_ptr = m_list->GetLast();
153  }
154 
155  void Set (ndNode* const node)
156  {
157  m_ptr = node;
158  }
159 
160  void operator++ ()
161  {
162  ndAssert (m_ptr);
163  m_ptr = m_ptr->m_next();
164  }
165 
166  void operator++ (ndInt32)
167  {
168  ndAssert (m_ptr);
169  m_ptr = m_ptr->GetNext();
170  }
171 
172  void operator-- ()
173  {
174  ndAssert (m_ptr);
175  m_ptr = m_ptr->GetPrev();
176  }
177 
178  void operator-- (ndInt32)
179  {
180  ndAssert (m_ptr);
181  m_ptr = m_ptr->GetPrev();
182  }
183 
184  T &operator* () const
185  {
186  return m_ptr->GetInfo();
187  }
188 
189  ndNode *GetNode() const
190  {
191  return m_ptr;
192  }
193 
194  private:
195  ndList *m_list;
196  ndNode *m_ptr;
197  };
198 
199  // ***********************************************************
200  // member functions
201  // ***********************************************************
202  public:
203  ndList ();
204  ~ndList ();
205 
206  operator ndInt32() const;
207  ndInt32 GetCount() const;
208  ndNode* GetLast() const;
209  ndNode* GetFirst() const;
210  ndNode* Append ();
211  ndNode* Append (ndNode* const node);
212  ndNode* Append (const T &element);
213  ndNode* Addtop ();
214  ndNode* Addtop (ndNode* const node);
215  ndNode* Addtop (const T &element);
216 
217  void RotateToEnd (ndNode* const node);
218  void RotateToBegin (ndNode* const node);
219  void InsertAfter (ndNode* const root, ndNode* const node);
220  void InsertBefore (ndNode* const root, ndNode* const node);
221 
222  ndNode* Find (const T &element) const;
223  ndNode* GetNodeFromInfo (T &m_info) const;
224  void Remove (ndNode* const node);
225  void Remove (const T &element);
226  void RemoveAll ();
227 
228  void Merge (ndList<T, allocator>& list);
229  void Unlink (ndNode* const node);
230  bool SanityCheck () const;
231 
232  static void FlushFreeList()
233  {
234  allocator::FlushFreeList(sizeof (ndNode));
235  }
236 
237  protected:
238  // ***********************************************************
239  // member variables
240  // ***********************************************************
241  private:
242  ndNode* m_first;
243  ndNode* m_last;
244  ndInt32 m_count;
245  friend class ndNode;
246 };
247 
248 template<class T, class allocator>
250  :ndClassAlloc()
251  ,m_first(nullptr)
252  ,m_last(nullptr)
253  ,m_count(0)
254 {
255 }
256 
257 template<class T, class allocator>
259 {
260  RemoveAll ();
261 }
262 
263 template<class T, class allocator>
264 ndInt32 ndList<T,allocator>::GetCount() const
265 {
266  return m_count;
267 }
268 
269 template<class T, class allocator>
270 ndList<T,allocator>::operator ndInt32() const
271 {
272  return m_first != nullptr;
273 }
274 
275 template<class T, class allocator>
277 {
278  return m_first;
279 }
280 
281 template<class T, class allocator>
283 {
284  return m_last;
285 }
286 
287 template<class T, class allocator>
288 typename ndList<T,allocator>::ndNode *ndList<T,allocator>::Append (ndNode* const node)
289 {
290  ndAssert (node->m_next == nullptr);
291  ndAssert (node->m_prev == nullptr);
292  m_count ++;
293  if (m_first == nullptr)
294  {
295  m_last = node;
296  m_first = node;
297  }
298  else
299  {
300  m_last->AddLast (node);
301  m_last = node;
302  }
303 #ifdef __ENABLE_DG_CONTAINERS_SANITY_CHECK
304  ndAssert (SanityCheck ());
305 #endif
306  return m_last;
307 }
308 
309 template<class T, class allocator>
311 {
312  m_count ++;
313  if (m_first == nullptr)
314  {
315  m_first = new ndNode(nullptr, nullptr);
316  m_last = m_first;
317  }
318  else
319  {
320  m_last = new ndNode(m_last, nullptr);
321  }
322 #ifdef __ENABLE_DG_CONTAINERS_SANITY_CHECK
323  ndAssert (SanityCheck ());
324 #endif
325  return m_last;
326 }
327 
328 template<class T, class allocator>
329 typename ndList<T,allocator>::ndNode *ndList<T,allocator>::Append (const T &element)
330 {
331  m_count ++;
332  if (m_first == nullptr)
333  {
334  m_first = new ndNode(element, nullptr, nullptr);
335  m_last = m_first;
336  }
337  else
338  {
339  m_last = new ndNode(element, m_last, nullptr);
340  }
341 #ifdef __ENABLE_DG_CONTAINERS_SANITY_CHECK
342  ndAssert (SanityCheck ());
343 #endif
344 
345  return m_last;
346 }
347 
348 template<class T, class allocator>
349 typename ndList<T,allocator>::ndNode *ndList<T,allocator>::Addtop (ndNode* const node)
350 {
351  ndAssert (node->m_next == nullptr);
352  ndAssert (node->m_prev == nullptr);
353  m_count ++;
354  if (m_last == nullptr)
355  {
356  m_last = node;
357  m_first = node;
358  }
359  else
360  {
361  m_first->AddFirst(node);
362  m_first = node;
363  }
364 #ifdef __ENABLE_DG_CONTAINERS_SANITY_CHECK
365  ndAssert (SanityCheck ());
366 #endif
367  return m_first;
368 }
369 
370 template<class T, class allocator>
372 {
373  m_count ++;
374  if (m_last == nullptr)
375  {
376  m_last = new ndNode(nullptr, nullptr);
377  m_first = m_last;
378  }
379  else
380  {
381  m_first = new ndNode(nullptr, m_first);
382  }
383 #ifdef __ENABLE_DG_CONTAINERS_SANITY_CHECK
384  ndAssert (SanityCheck ());
385 #endif
386  return m_first;
387 }
388 
389 template<class T, class allocator>
390 typename ndList<T,allocator>::ndNode *ndList<T,allocator>::Addtop (const T &element)
391 {
392  m_count ++;
393  if (m_last == nullptr)
394  {
395  m_last = new ndNode(element, nullptr, nullptr);
396  m_first = m_last;
397  }
398  else
399  {
400  m_first = new ndNode(element, nullptr, m_first);
401  }
402 #ifdef __ENABLE_DG_CONTAINERS_SANITY_CHECK
403  ndAssert (SanityCheck ());
404 #endif
405  return m_first;
406 }
407 
408 template<class T, class allocator>
409 void ndList<T,allocator>::InsertAfter (ndNode* const root, ndNode* const node)
410 {
411  ndAssert (root);
412  if (node != root)
413  {
414  if (root->m_next != node)
415  {
416  if (node == m_first)
417  {
418  m_first = node->m_next;
419  }
420  if (node == m_last)
421  {
422  m_last = node->m_prev;
423  }
424  node->Unlink ();
425 
426  node->m_prev = root;
427  node->m_next = root->m_next;
428  if (root->m_next)
429  {
430  root->m_next->m_prev = node;
431  }
432  root->m_next = node;
433 
434  if (node->m_next == nullptr)
435  {
436  m_last = node;
437  }
438 
439  ndAssert (m_last);
440  ndAssert (!m_last->m_next);
441  ndAssert (m_first);
442  ndAssert (!m_first->m_prev);
443  ndAssert (SanityCheck ());
444  }
445  }
446 }
447 
448 template<class T, class allocator>
449 void ndList<T,allocator>::InsertBefore (ndNode* const root, ndNode* const node)
450 {
451  ndAssert (root);
452  if (node != root)
453  {
454  if (root->m_prev != node)
455  {
456  if (node == m_last)
457  {
458  m_last = node->m_prev;
459  }
460  if (node == m_first) {
461  m_first = node->m_next;
462  }
463  node->Unlink ();
464 
465  node->m_next = root;
466  node->m_prev = root->m_prev;
467  if (root->m_prev)
468  {
469  root->m_prev->m_next = node;
470  }
471  root->m_prev = node;
472 
473  if (node->m_prev == nullptr) {
474  m_first = node;
475  }
476 
477  ndAssert (m_first);
478  ndAssert (!m_first->m_prev);
479  ndAssert (m_last);
480  ndAssert (!m_last->m_next);
481  ndAssert (SanityCheck ());
482  }
483  }
484 }
485 
486 template<class T, class allocator>
487 void ndList<T,allocator>::RotateToEnd (ndNode* const node)
488 {
489  if (node != m_last)
490  {
491  if (m_last != m_first)
492  {
493  if (node == m_first)
494  {
495  m_first = m_first->GetNext();
496  }
497  node->Unlink();
498  m_last->AddLast(node);
499  m_last = node;
500  }
501  }
502 
503 #ifdef __ENABLE_DG_CONTAINERS_SANITY_CHECK
504  ndAssert (SanityCheck ());
505 #endif
506 }
507 
508 template<class T, class allocator>
509 void ndList<T,allocator>::RotateToBegin (ndNode* const node)
510 {
511  if (node != m_first)
512  {
513  if (m_last != m_first)
514  {
515  if (node == m_last)
516  {
517  m_last = m_last->GetPrev();
518  }
519  node->Unlink();
520  m_first->AddFirst(node);
521  m_first = node;
522  }
523  }
524 
525 #ifdef __ENABLE_DG_CONTAINERS_SANITY_CHECK
526  ndAssert (SanityCheck ());
527 #endif
528 }
529 
530 template<class T, class allocator>
531 typename ndList<T,allocator>::ndNode *ndList<T,allocator>::Find (const T &element) const
532 {
533  ndNode *node;
534  for (node = m_first; node; node = node->GetNext())
535  {
536  if (element == node->m_info)
537  {
538  break;
539  }
540  }
541  return node;
542 }
543 
544 template<class T, class allocator>
546 {
547  ndNode* const node = (ndNode *) &info;
548  ndInt64 offset = ((char*) &node->m_info) - ((char *) node);
549  ndNode* const retnode = (ndNode *) (((char *) node) - offset);
550 
551  ndAssert (&retnode->GetInfo () == &info);
552  return retnode;
553 }
554 
555 template<class T, class allocator>
556 void ndList<T,allocator>::Remove (const T &element)
557 {
558  ndNode *const node = Find (element);
559  if (node)
560  {
561  Remove (node);
562  }
563 }
564 
565 template<class T, class allocator>
566 void ndList<T,allocator>::Unlink (ndNode* const node)
567 {
568  ndAssert (node);
569 
570  m_count --;
571  ndAssert (m_count >= 0);
572 
573  if (node == m_first)
574  {
575  m_first = m_first->GetNext();
576  }
577  if (node == m_last)
578  {
579  m_last = m_last->GetPrev();
580  }
581  node->Unlink();
582 
583 #ifdef __ENABLE_DG_CONTAINERS_SANITY_CHECK
584  ndAssert (SanityCheck ());
585 #endif
586 }
587 
588 template<class T, class allocator>
590 {
591  m_count += list.m_count;
592  if (list.m_first)
593  {
594  list.m_first->m_prev = m_last;
595  }
596  if (m_last)
597  {
598  m_last->m_next = list.m_first;
599  }
600  m_last = list.m_last;
601  if (!m_first)
602  {
603  m_first = list.m_first;
604  }
605 
606  list.m_count = 0;
607  list.m_last = nullptr;
608  list.m_first = nullptr;
609 #ifdef __ENABLE_DG_CONTAINERS_SANITY_CHECK
610  ndAssert (SanityCheck ());
611 #endif
612 }
613 
614 template<class T, class allocator>
615 void ndList<T,allocator>::Remove (ndNode* const node)
616 {
617  Unlink (node);
618  delete node;
619 }
620 
621 template<class T, class allocator>
623 {
624  for (ndNode *node = m_first; node; node = m_first)
625  {
626  m_count --;
627  m_first = node->GetNext();
628  node->Unlink();
629  delete node;
630  }
631  ndAssert (m_count == 0);
632  m_last = nullptr;
633  m_first = nullptr;
634 }
635 
636 template<class T, class allocator>
638 {
639  #ifdef _DEBUG
640  ndInt32 tCount = 0;
641  for (ndNode * node = m_first; node; node = node->GetNext())
642  {
643  tCount ++;
644  if (node->GetPrev()) {
645  ndAssert (node->GetPrev() != node->GetNext());
646  if (node->GetPrev()->GetNext() != node)
647  {
648  ndAssert (0);
649  return false;
650  }
651  }
652  if (node->GetNext())
653  {
654  ndAssert (node->GetPrev() != node->GetNext());
655  if (node->GetNext()->GetPrev() != node)
656  {
657  ndAssert (0);
658  return false;
659  }
660  }
661  }
662  if (tCount != m_count)
663  {
664  ndAssert (0);
665  return false;
666  }
667  #endif
668  return true;
669 }
670 
671 #endif
672 
673 
ndClassAlloc
Base class for providing memory allocation for all other engine classes.
Definition: ndClassAlloc.h:30
ndList
Definition: ndList.h:33
ndList::ndNode
Definition: ndList.h:36
ndList::Iterator
Definition: ndList.h:123