Newton Dynamics  4.00
ndTree.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_TREE_H__
23 #define __ND_TREE_H__
24 
25 #include "ndCoreStdafx.h"
26 #include "ndTypes.h"
27 #include "ndUtils.h"
28 #include "ndMemory.h"
29 #include "ndClassAlloc.h"
30 #include "ndContainersAlloc.h"
31 
32 // Note: this is a low level class for ndTree use only
33 // unpredictable result will happen if you attempt to manipulate
34 // any member of this class
36 {
37  public:
38  enum REDBLACK_COLOR
39  {
40  RED = true,
41  BLACK = false
42  };
43 
45  {
46  }
47 
48  virtual ~ndRedBackNode ()
49  {
50  }
51 
52  D_CORE_API void RemoveAllLow ();
53  D_CORE_API void RotateLeft(ndRedBackNode** const head);
54  D_CORE_API void RotateRight(ndRedBackNode** const head);
55  D_CORE_API void RemoveFixup (ndRedBackNode* const node, ndRedBackNode* * const head);
56 
57  D_CORE_API ndRedBackNode (ndRedBackNode* const parent);
58  D_CORE_API inline void Initdata (ndRedBackNode* const parent);
59  D_CORE_API inline void SetColor (REDBLACK_COLOR color);
60  D_CORE_API REDBLACK_COLOR GetColor () const;
61  D_CORE_API ndUnsigned32 IsInTree () const;
62  D_CORE_API inline void SetInTreeFlag (ndUnsigned32 flag);
63 
64  D_CORE_API void RemoveAll ();
65  D_CORE_API ndRedBackNode* Prev() const;
66  D_CORE_API ndRedBackNode* Next() const;
67  D_CORE_API ndRedBackNode* Minimum() const;
68  D_CORE_API ndRedBackNode* Maximum() const;
69  D_CORE_API void Remove (ndRedBackNode** const head);
70  D_CORE_API void Unlink (ndRedBackNode** const head);
71  D_CORE_API void InsertFixup(ndRedBackNode** const head);
72 
73  ndRedBackNode* m_left;
74  ndRedBackNode* m_right;
75  ndRedBackNode* m_parent;
76  ndUnsigned32 m_color : 1;
77  ndUnsigned32 m_inTree : 1;
78 };
79 
80 template<class OBJECT, class KEY, class allocator = ndContainersAlloc<OBJECT> >
81 class ndTree: public ndClassAlloc
82 {
83  public:
84  class ndNode: public allocator, public ndRedBackNode
85  {
86  ndNode(const KEY &key, ndNode* parentNode)
87  :allocator()
88  ,ndRedBackNode(parentNode), m_info(), m_key(key)
89  {
90  }
91 
92  ndNode (const OBJECT &info, const KEY &key, ndNode* parentNode)
93  :allocator()
94  ,ndRedBackNode(parentNode), m_info (info), m_key (key)
95  {
96  }
97 
98  ~ndNode ()
99  {
100  }
101 
102  ndNode* GetLeft () const
103  {
104  return (ndNode* )ndRedBackNode::m_left;
105  }
106 
107  ndNode* GetRight () const
108  {
109  return (ndNode* )ndRedBackNode::m_right;
110  }
111 
112  ndNode* GetParent ()
113  {
114  return (ndNode* )ndRedBackNode::m_parent;
115  }
116 
117  void SetLeft (ndNode* const node)
118  {
119  ndRedBackNode::m_left = node;
120  }
121 
122  void SetRight (ndNode* const node)
123  {
124  ndRedBackNode::m_right = node;
125  }
126 
127  void SetParent (ndNode* const node)
128  {
129  ndRedBackNode::m_parent = node;
130  }
131 
132  public:
133  const KEY& GetKey() const
134  {
135  return m_key;
136  }
137 
138  OBJECT& GetInfo()
139  {
140  return m_info;
141  }
142 
143  const OBJECT& GetInfo() const
144  {
145  return m_info;
146  }
147 
148  private:
149  OBJECT m_info;
150  KEY m_key;
151  friend class ndTree<OBJECT, KEY, allocator>;
152  };
153 
154  class Iterator
155  {
156  public:
158  {
159  m_ptr = nullptr;
160  m_tree = &me;
161  }
162 
163  ~Iterator()
164  {
165  }
166 
167  void Begin()
168  {
169  m_ptr = m_tree->Minimum();
170  }
171 
172  void End()
173  {
174  m_ptr = m_tree->Maximum();
175  }
176 
177  void Set (ndNode* const node)
178  {
179  m_ptr = node;
180  }
181 
182  operator ndInt32() const
183  {
184  return m_ptr != nullptr;
185  }
186 
187  void operator++ ()
188  {
189  ndAssert (m_ptr);
190  m_ptr = m_ptr->Next();
191  }
192 
193  void operator++ (ndInt32)
194  {
195  ndAssert (m_ptr);
196  m_ptr = m_ptr->Next();
197  }
198 
199  void operator-- ()
200  {
201  ndAssert (m_ptr);
202  m_ptr = m_ptr->Prev();
203  }
204 
205  void operator-- (ndInt32)
206  {
207  ndAssert (m_ptr);
208  m_ptr = m_ptr->Prev();
209  }
210 
211  OBJECT &operator* () const
212  {
213  return ((ndNode*)m_ptr)->GetInfo();
214  }
215 
216  ndNode* GetNode() const
217  {
218  return (ndNode*)m_ptr;
219  }
220 
221  KEY GetKey () const
222  {
223  ndNode* const tmp = (ndNode*)m_ptr;
224  //return tmp ? tmp->GetKey() : KEY(0);
225  return tmp ? tmp->GetKey() : KEY();
226  }
227 
228  private:
229  ndRedBackNode* m_ptr;
230  const ndTree* m_tree;
231 
232  };
233 
234  // ***********************************************************
235  // member functions
236  // ***********************************************************
237  public:
238  ndTree ();
239  ~ndTree ();
240 
241  operator ndInt32() const;
242  ndInt32 GetCount() const;
243 
244  ndNode* GetRoot () const;
245  ndNode* Minimum () const;
246  ndNode* Maximum () const;
247 
248  ndNode* Find (const KEY& key) const;
249  ndNode* FindGreater (const KEY& key) const;
250  ndNode* FindLessEqual(const KEY& key) const;
251  ndNode* FindGreaterEqual (const KEY& key) const;
252  ndNode* FindCreate(const KEY& key, bool& wasFound);
253 
254  ndNode* GetNodeFromInfo (OBJECT &info) const;
255 
256  ndNode* Insert(const KEY& key);
257  ndNode* Insert(ndNode* const node, const KEY& key);
258  ndNode* Insert(const OBJECT &element, const KEY& key);
259  ndNode* Insert (const OBJECT &element, const KEY& key, bool& wasFound);
260 
261  ndNode* Replace (OBJECT &element, const KEY& key);
262  ndNode* ReplaceKey (const KEY& oldKey, const KEY& newKey);
263  ndNode* ReplaceKey (ndNode* const node, const KEY& key);
264 
265  void RemoveAll();
266  void Remove (const KEY& key);
267  void Remove (ndNode* const node);
268 
269  void Unlink (ndNode* const node);
270  void SwapInfo (ndTree& tree);
271 
272  bool SanityCheck () const;
273 
274  static void FlushFreeList()
275  {
276  allocator::FlushFreeList(sizeof(ndNode));
277  }
278 
279  // ***********************************************************
280  // member variables
281  // ***********************************************************
282  private:
283  ndNode* m_head;
284  ndInt32 m_count;
285 
286  ndInt32 CompareKeys (const KEY &key0, const KEY &key1) const;
287  bool SanityCheck (ndNode* const ptr, ndInt32 height) const;
288 
289  friend class ndNode;
290 };
291 
292 inline ndRedBackNode::ndRedBackNode (ndRedBackNode* const parent)
293 {
294  Initdata (parent);
295 }
296 
297 inline void ndRedBackNode::Initdata (ndRedBackNode* const parent)
298 {
299  SetColor (RED);
300  SetInTreeFlag (true);
301  m_left = nullptr;
302  m_right = nullptr;
303  m_parent = parent;
304 }
305 
306 inline void ndRedBackNode::SetColor (ndRedBackNode::REDBLACK_COLOR color)
307 {
308  m_color = color;
309 }
310 
311 inline ndRedBackNode::REDBLACK_COLOR ndRedBackNode::GetColor () const
312 {
313  return REDBLACK_COLOR (m_color);
314 }
315 
316 inline void ndRedBackNode::SetInTreeFlag (ndUnsigned32 flag)
317 {
318  m_inTree = flag;
319 }
320 
321 inline ndUnsigned32 ndRedBackNode::IsInTree () const
322 {
323  return m_inTree;
324 }
325 
326 template<class OBJECT, class KEY, class allocator>
328  :ndClassAlloc()
329  ,m_head(nullptr)
330  ,m_count(0)
331 {
332 }
333 
334 template<class OBJECT, class KEY, class allocator>
336 {
337  RemoveAll();
338 }
339 
340 template<class OBJECT, class KEY, class allocator>
342 {
343  return m_head != nullptr;
344 }
345 
346 template<class OBJECT, class KEY, class allocator>
348 {
349  return m_count;
350 }
351 
352 template<class OBJECT, class KEY, class allocator>
354 {
355  return m_head ? (ndNode* )m_head->Minimum() : nullptr;
356 }
357 
358 template<class OBJECT, class KEY, class allocator>
360 {
361  return m_head ? (ndNode* )m_head->Maximum() : nullptr;
362 }
363 
364 template<class OBJECT, class KEY, class allocator>
366 {
367  return m_head;
368 }
369 
370 template<class OBJECT, class KEY, class allocator>
372 {
373  if (m_head == nullptr)
374  {
375  return nullptr;
376  }
377 
378  ndNode* ptr = m_head;
379  while (ptr != nullptr)
380  {
381  if (key < ptr->m_key)
382  {
383  ndAssert (CompareKeys (ptr->m_key, key) == -1) ;
384  ptr = ptr->GetLeft();
385  }
386  else if (key > ptr->m_key)
387  {
388  ndAssert (CompareKeys (ptr->m_key, key) == 1) ;
389  ptr = ptr->GetRight();
390  }
391  else
392  {
393  ndAssert (CompareKeys (ptr->m_key, key) == 0) ;
394  break;
395  }
396  }
397  return ptr;
398 }
399 
400 template<class OBJECT, class KEY, class allocator>
402 {
403  ndNode* const node = (ndNode* ) &info;
404  ndInt64 offset = ((char*) &node->m_info) - ((char *) node);
405  ndNode* const retnode = (ndNode* ) (((char *) node) - offset);
406 
407  ndAssert (retnode->IsInTree ());
408  ndAssert (&retnode->GetInfo () == &info);
409  return (retnode->IsInTree ()) ? retnode : nullptr;
410 }
411 
412 template<class OBJECT, class KEY, class allocator>
414 {
415  if (m_head == nullptr)
416  {
417  return nullptr;
418  }
419 
420  ndNode* prev = nullptr;
421  ndNode* ptr = m_head;
422 
423  while (ptr != nullptr)
424  {
425  if (key < ptr->m_key)
426  {
427  prev = ptr;
428  ptr = ptr->GetLeft();
429  }
430  else
431  {
432  ptr = ptr->GetRight();
433  }
434  }
435 
436 #ifdef __ENABLE_DG_CONTAINERS_SANITY_CHECK
437  if (prev)
438  {
439  Iterator iter (*this);
440  for (iter.Begin(); iter.GetNode() != prev; iter ++)
441  {
442  KEY key1 = iter.GetKey();
443  ndAssert (key1 <= key);
444  }
445  for (; iter.GetNode(); iter ++)
446  {
447  KEY key1 = iter.GetKey();
448  ndAssert (key1 > key);
449  }
450  }
451 #endif
452 
453  return (ndNode* )prev;
454 }
455 
456 template<class OBJECT, class KEY, class allocator>
458 {
459  if (m_head == nullptr)
460  {
461  return nullptr;
462  }
463 
464  ndNode* prev = nullptr;
465  ndNode* ptr = m_head;
466 
467  while (ptr != nullptr)
468  {
469  if (key == ptr->m_key)
470  {
471  return ptr;
472  }
473  if (key < ptr->m_key)
474  {
475  prev = ptr;
476  ptr = ptr->GetLeft();
477  }
478  else
479  {
480  ptr = ptr->GetRight();
481  }
482  }
483 
484 #ifdef __ENABLE_DG_CONTAINERS_SANITY_CHECK
485  if (prev)
486  {
487  Iterator iter (*this);
488  for (iter.Begin(); iter.GetNode() != prev; iter ++)
489  {
490  KEY key1 = iter.GetKey();
491  ndAssert (key1 <= key);
492  }
493  for (; iter.GetNode(); iter ++)
494  {
495  KEY key1 = iter.GetKey();
496  ndAssert (key1 >= key);
497  }
498  }
499 #endif
500 
501  return (ndNode* )prev;
502 }
503 
504 template<class OBJECT, class KEY, class allocator>
506 {
507  if (m_head == nullptr)
508  {
509  return nullptr;
510  }
511 
512  ndNode* prev = nullptr;
513  ndNode* ptr = m_head;
514 
515  while (ptr != nullptr)
516  {
517  if (key == ptr->m_key)
518  {
519  return ptr;
520  }
521 
522  if (key < ptr->m_key)
523  {
524  ptr = ptr->GetLeft();
525  }
526  else
527  {
528  prev = ptr;
529  ptr = ptr->GetRight();
530  }
531 
532  }
533 
534 #ifdef __ENABLE_DG_CONTAINERS_SANITY_CHECK
535  if (prev)
536  {
537  Iterator iter (*this);
538  for (iter.End(); iter.GetNode() != prev; iter --)
539  {
540  KEY key1 = iter.GetKey();
541  ndAssert (key1 >= key);
542  }
543  for (; iter.GetNode(); iter --)
544  {
545  KEY key1 = iter.GetKey();
546  ndAssert (key1 < key);
547  }
548  }
549 #endif
550 
551  return (ndNode* )prev;
552 }
553 
554 template<class OBJECT, class KEY, class allocator>
555 typename ndTree<OBJECT, KEY, allocator>::ndNode* ndTree<OBJECT, KEY, allocator>::Insert (const OBJECT &element, const KEY& key, bool& wasFound)
556 {
557  ndNode* parent = nullptr;
558  ndNode* ptr = m_head;
559  ndInt32 val = 0;
560  while (ptr != nullptr)
561  {
562  parent = ptr;
563 
564  if (key < ptr->m_key)
565  {
566  ndAssert (CompareKeys (ptr->m_key, key) == -1) ;
567  val = -1;
568  ptr = ptr->GetLeft();
569  }
570  else if (key > ptr->m_key)
571  {
572  ndAssert (CompareKeys (ptr->m_key, key) == 1) ;
573  val = 1;
574  ptr = ptr->GetRight();
575  }
576  else
577  {
578  ndAssert (CompareKeys (ptr->m_key, key) == 0) ;
579  wasFound = true;
580  return ptr;
581  }
582  }
583 
584  m_count ++;
585  wasFound = false;
586  ptr = new ndNode (element, key, parent);
587  if (!parent)
588  {
589  m_head = ptr;
590  }
591  else
592  {
593  if (val < 0)
594  {
595  parent->m_left = ptr;
596  }
597  else
598  {
599  parent->m_right = ptr;
600  }
601  }
602 
603  ndNode** const headPtr = (ndNode**) &m_head;
604  ptr->InsertFixup ((ndRedBackNode**)headPtr);
605  return ptr;
606 }
607 
608 template<class OBJECT, class KEY, class allocator>
610 {
611  ndNode* parent = nullptr;
612  ndNode* ptr = m_head;
613  ndInt32 val = 0;
614  while (ptr != nullptr)
615  {
616  parent = ptr;
617  if (key < ptr->m_key)
618  {
619  ndAssert(CompareKeys(ptr->m_key, key) == -1);
620  val = -1;
621  ptr = ptr->GetLeft();
622  }
623  else if (key > ptr->m_key)
624  {
625  ndAssert(CompareKeys(ptr->m_key, key) == 1);
626  val = 1;
627  ptr = ptr->GetRight();
628  }
629  else
630  {
631  ndAssert(CompareKeys(ptr->m_key, key) == 0);
632  wasFound = true;
633  return ptr;
634  }
635  }
636 
637  m_count++;
638  wasFound = false;
639  ptr = new ndNode(key, parent);
640  if (!parent)
641  {
642  m_head = ptr;
643  }
644  else
645  {
646  if (val < 0)
647  {
648  parent->m_left = ptr;
649  }
650  else
651  {
652  parent->m_right = ptr;
653  }
654  }
655 
656  ndNode** const headPtr = (ndNode**)&m_head;
657  ptr->InsertFixup((ndRedBackNode**)headPtr);
658  return ptr;
659 }
660 
661 template<class OBJECT, class KEY, class allocator>
662 typename ndTree<OBJECT, KEY, allocator>::ndNode* ndTree<OBJECT, KEY, allocator>::Insert (const OBJECT &element, const KEY& key)
663 {
664  bool foundState;
665 
666  ndNode* const node = Insert (element, key, foundState);
667  if (foundState)
668  {
669  return nullptr;
670  }
671  return node;
672 }
673 
674 template<class OBJECT, class KEY, class allocator>
676 {
677  OBJECT element;
678  return Insert(element, key);
679 }
680 
681 template<class OBJECT, class KEY, class allocator>
683 {
684  ndInt32 val = 0;
685  ndNode* ptr = m_head;
686  ndNode* parent = nullptr;
687  while (ptr != nullptr)
688  {
689  parent = ptr;
690 
691  if (key < ptr->m_key)
692  {
693  ndAssert (CompareKeys (ptr->m_key, key) == -1) ;
694  val = -1;
695  ptr = ptr->GetLeft();
696  }
697  else if (key > ptr->m_key)
698  {
699  ndAssert (CompareKeys (ptr->m_key, key) == 1) ;
700  val = 1;
701  ptr = ptr->GetRight();
702  }
703  else
704  {
705  ndAssert (CompareKeys (ptr->m_key, key) == 0) ;
706  return nullptr;
707  }
708  }
709 
710  m_count ++;
711 
712  ptr = node;
713  ptr->m_key = key;
714  ptr->Initdata (parent);
715 
716  if (!parent)
717  {
718  m_head = ptr;
719  }
720  else
721  {
722  if (val < 0)
723  {
724  parent->m_left = ptr;
725  }
726  else
727  {
728  parent->m_right = ptr;
729  }
730  }
731 
732  ndNode** const headPtr = (ndNode**) &m_head;
733  ptr->InsertFixup ((ndRedBackNode**)headPtr);
734  return ptr;
735 }
736 
737 template<class OBJECT, class KEY, class allocator>
739 {
740  ndNode* parent = nullptr;
741  ndNode* ptr = m_head;
742  ndInt32 val = 0;
743 
744  while (ptr != nullptr)
745  {
746  parent = ptr;
747 
748  ndAssert (0);
749  val = CompareKeys (ptr->m_key, key);
750  if (val == 0)
751  {
752  ptr->m_info = element;
753  return ptr;
754  }
755  if (val < 0)
756  {
757  ptr = ptr->GetLeft();
758  }
759  else
760  {
761  ptr = ptr->GetRight();
762  }
763  }
764 
765  ptr = new ndNode (element, key, parent);
766  if (!parent)
767  {
768  m_head = ptr;
769  }
770  else
771  {
772  if (val < 0)
773  {
774  parent->m_left = ptr;
775  }
776  else
777  {
778  parent->m_right = ptr;
779  }
780  }
781 
782  ndNode** const headPtr = (ndNode**) &m_head;
783  ptr->InsertFixup ((ndRedBackNode**)headPtr );
784  return ptr;
785 }
786 
787 template<class OBJECT, class KEY, class allocator>
789 {
790  Unlink (node);
791  ndNode* const ptr = Insert (node, key);
792  ndAssert (ptr);
793  return ptr;
794 }
795 
796 template<class OBJECT, class KEY, class allocator>
797 typename ndTree<OBJECT, KEY, allocator>::ndNode* ndTree<OBJECT, KEY, allocator>::ReplaceKey (const KEY& oldKey, const KEY& newKey)
798 {
799  ndNode* const node = Find (oldKey);
800  return node ? ReplaceKey (node, newKey) : nullptr;
801 }
802 
803 template<class OBJECT, class KEY, class allocator>
805 {
806  m_count --;
807 
808  ndNode** const headPtr = (ndNode**) &m_head;
809  node->Unlink ((ndRedBackNode**)headPtr);
810  ndAssert (!Find (node->GetKey()));
811 }
812 
813 template<class OBJECT, class KEY, class allocator>
815 {
816  m_count --;
817  ndNode** const headPtr = (ndNode**) &m_head;
818  node->Remove ((ndRedBackNode**)headPtr);
819 }
820 
821 template<class OBJECT, class KEY, class allocator>
822 void ndTree<OBJECT, KEY, allocator>::Remove (const KEY& key)
823 {
824  // find node in tree
825  ndNode* const node = Find (key);
826  if (node)
827  {
828  Remove(node);
829  }
830 }
831 
832 template<class OBJECT, class KEY, class allocator>
834 {
835  if (m_head)
836  {
837  m_count = 0;
838  m_head->RemoveAll ();
839  m_head = nullptr;
840  }
841 }
842 
843 template<class OBJECT, class KEY, class allocator>
845 {
846  return SanityCheck (m_head, 0);
847 }
848 
849 template<class OBJECT, class KEY, class allocator>
850 bool ndTree<OBJECT, KEY, allocator>::SanityCheck (typename ndTree<OBJECT, KEY, allocator>::ndNode* const ptr, ndInt32 height) const
851 {
852  if (!ptr)
853  {
854  return true;
855  }
856 
857  if (!ptr->IsInTree())
858  {
859  return false;
860  }
861 
862  if (ptr->m_left)
863  {
864  if (CompareKeys (ptr->m_key, ptr->GetLeft()->m_key) > 0)
865  {
866  return false;
867  }
868  }
869 
870  if (ptr->m_right)
871  {
872  if (CompareKeys (ptr->m_key, ptr->GetRight()->m_key) < 0)
873  {
874  return false;
875  }
876  }
877 
878  if (ptr->GetColor() == ndNode::BLACK)
879  {
880  height ++;
881  }
882  else if (!((!ptr->m_left || (ptr->m_left->GetColor() == ndNode::BLACK)) &&
883  (!ptr->m_right || (ptr->m_right->GetColor() == ndNode::BLACK))))
884  {
885  return false;
886  }
887 
888  if (!ptr->m_left && !ptr->m_right)
889  {
890  ndInt32 bh = 0;
891  for (ndNode* x = ptr; x; x = x->GetParent())
892  {
893  if (x->GetColor() == ndNode::BLACK)
894  {
895  bh ++;
896  }
897  }
898  if (bh != height)
899  {
900  return false;
901  }
902  }
903 
904  if (ptr->m_left && !SanityCheck (ptr->GetLeft(), height))
905  {
906  return false;
907  }
908 
909  if (ptr->m_right && !SanityCheck (ptr->GetRight(), height))
910  {
911  return false;
912  }
913  return true;
914 }
915 
916 template<class OBJECT, class KEY, class allocator>
917 ndInt32 ndTree<OBJECT, KEY, allocator>::CompareKeys (const KEY &key0, const KEY &key1) const
918 {
919  if (key1 < key0)
920  {
921  return - 1;
922  }
923  if (key1 > key0)
924  {
925  return 1;
926  }
927  return 0;
928 }
929 
930 template<class OBJECT, class KEY, class allocator>
932 {
933  ndSwap (m_head, tree.m_head);
934  ndSwap (m_count, tree.m_count);
935 }
936 
937 //template<class OBJECT, class KEY, class allocator> ndInt32 ndTree<OBJECT, KEY, allocator>::m_size = 0;
938 //template<class OBJECT, class KEY, class allocator> dgMemoryAllocator* ndTree<OBJECT, KEY, allocator>::m_staticAllocator = nullptr;
939 
940 
941 #endif
942 
943 
ndClassAlloc
Base class for providing memory allocation for all other engine classes.
Definition: ndClassAlloc.h:30
ndTree::ndNode
Definition: ndTree.h:85
ndTree::Iterator
Definition: ndTree.h:155
ndTree
Definition: ndTree.h:82
ndRedBackNode
Definition: ndTree.h:36