Newton Dynamics  4.00
ndHeap.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 /****************************************************************************
23 *
24 * Visual C++ 6.0 created by: Julio Jerez
25 *
26 ****************************************************************************/
27 #ifndef __D_HEAP_H__
28 #define __D_HEAP_H__
29 
30 #include "ndCoreStdafx.h"
31 #include "ndTypes.h"
32 #include "ndMemory.h"
33 #include "ndClassAlloc.h"
34 
35 //#define ND_HEAP_DEBUG_CHECK
36 
37 
38 template <class dItem, class dKey>
39 class ndHeap : public ndClassAlloc
40 {
41  public:
42  ndHeap(ndInt32 maxElements);
43  ndHeap(const void * const buffer, ndInt32 sizeInBytes);
44  ~ndHeap();
45 
46  void Flush();
47  dKey MaxValue() const;
48  dKey Value(ndInt32 i = 0) const;
49  ndInt32 GetCount() const;
50  ndInt32 GetMaxCount() const;
51  const dItem& operator[] (ndInt32 i) const;
52  ndInt32 Find(dItem &obj);
53  ndInt32 Find(dKey key);
54 
55  void Pop();
56  void Sort();
57  void Remove(ndInt32 Index);
58  void Push(dItem &obj, dKey key);
59  bool SanityCheck();
60 
61  protected:
62  struct dRecord
63  {
64  dRecord(dKey key, const dItem& obj)
65  :m_key(key)
66  ,m_obj(obj)
67  {
68  }
69 
70  dKey m_key;
71  dItem m_obj;
72  };
73 
74  dRecord* m_pool;
75  ndInt32 m_curCount;
76  ndInt32 m_maxCount;
77  bool m_bufferIsOwnned;
78 };
79 
80 
81 
82 // *************************
83 //
84 // implementation
85 //
86 // *************************
87 
88 template <class dItem, class dKey>
89 ndHeap<dItem, dKey>::ndHeap(ndInt32 maxElements)
90  :ndClassAlloc()
91  ,m_pool((dRecord *)ndMemory::Malloc(maxElements * sizeof(dRecord)))
92  ,m_curCount(0)
93  ,m_maxCount(maxElements)
94  ,m_bufferIsOwnned(true)
95 {
96  Flush();
97 }
98 
99 template <class dItem, class dKey>
100 ndHeap<dItem, dKey>::ndHeap(const void * const buffer, ndInt32 sizeInBytes)
101  :ndClassAlloc()
102  ,m_pool((dRecord *)buffer)
103  ,m_curCount(0)
104  ,m_maxCount(ndInt32(sizeInBytes / sizeof(dRecord)))
105  ,m_bufferIsOwnned(false)
106 {
107  Flush();
108 }
109 
110 template <class dItem, class dKey>
112 {
113  if (m_bufferIsOwnned)
114  {
115  ndMemory::Free(m_pool);
116  }
117 }
118 
119 template <class dItem, class dKey>
120 dKey ndHeap<dItem, dKey>::Value(ndInt32 i) const
121 {
122  return m_pool[i].m_key;
123 }
124 
125 template <class dItem, class dKey>
126 ndInt32 ndHeap<dItem, dKey>::GetCount() const
127 {
128  return m_curCount;
129 }
130 
131 template <class dItem, class dKey>
133 {
134  m_curCount = 0;
135 
136 #ifdef _DEBUG
137  // ndHeap<dItem,dKey>::m_pool[ndHeap<dItem,dKey>::m_curCount].m_key = dKey (0);
138 #endif
139 }
140 
141 template <class dItem, class dKey>
143 {
144  return m_pool[0].m_key;
145 }
146 
147 template <class dItem, class dKey>
148 ndInt32 ndHeap<dItem, dKey>::GetMaxCount() const
149 {
150  return m_maxCount;
151 }
152 
153 template <class dItem, class dKey>
154 ndInt32 ndHeap<dItem, dKey>::Find(dItem &obj)
155 {
156  // For now let perform a linear search
157  // this is efficient if the size of the heap is small
158  // ex: m_curCount < 32
159  // this will be change to a binary search in the heap should the
160  // the size of the heap get larger than 32
161  // ndAssert (m_curCount <= 32);
162  for (ndInt32 i = 0; i < m_curCount; ++i)
163  {
164  if (m_pool[i].obj == obj)
165  {
166  return i;
167  }
168  }
169  return -1;
170 }
171 
172 template <class dItem, class dKey>
173 ndInt32 ndHeap<dItem, dKey>::Find(dKey key)
174 {
175  // ex: m_curCount < 32
176  // this will be change to a binary search in the heap should the
177  // the size of the heap get larger than 32
178  ndAssert(m_curCount <= 32);
179  for (ndInt32 i = 0; i < m_curCount; ++i)
180  {
181  if (m_pool[i].m_key == key)
182  {
183  return i;
184  }
185  }
186  return -1;
187 }
188 
189 template <class dItem, class dKey>
190 const dItem& ndHeap<dItem, dKey>::operator[] (ndInt32 i) const
191 {
192  ndAssert(i <= m_curCount);
193  return m_pool[i].m_obj;
194 }
195 
196 template <class dItem, class dKey>
198 {
199  #ifdef ND_HEAP_DEBUG_CHECK
200  for (ndInt32 i = 0; i < m_curCount; ++i)
201  {
202  ndInt32 i1 = 2 * i + 1;
203  ndInt32 i2 = 2 * i + 2;
204  if ((i1 < m_curCount) && (ndHeap<dItem, dKey>::m_pool[i].m_key < ndHeap<dItem, dKey>::m_pool[i1].m_key))
205  {
206  return false;
207  }
208  if ((i2 < m_curCount) && (ndHeap<dItem, dKey>::m_pool[i].m_key < ndHeap<dItem, dKey>::m_pool[i2].m_key))
209  {
210  return false;
211  }
212  }
213  #endif
214  return true;
215 }
216 
217 template <class dItem, class dKey>
218 void ndHeap<dItem, dKey>::Push(dItem &obj, dKey key)
219 {
221 
223  for (ndInt32 j = 0; i; i = j)
224  {
225  j = i >> 1;
226  if (!j || (ndHeap<dItem, dKey>::m_pool[j - 1].m_key > key))
227  {
228  break;
229  }
231  }
232  ndAssert(i);
233  ndHeap<dItem, dKey>::m_pool[i - 1].m_key = key;
234  ndHeap<dItem, dKey>::m_pool[i - 1].m_obj = obj;
235 
236  ndAssert(SanityCheck());
237 }
238 
239 template <class dItem, class dKey>
241 {
242  Remove(0);
243 }
244 
245 template <class dItem, class dKey>
246 void ndHeap<dItem, dKey>::Remove(ndInt32 index)
247 {
250  while (index && ndHeap<dItem, dKey>::m_pool[(index - 1) >> 1].m_key < ndHeap<dItem, dKey>::m_pool[index].m_key)
251  {
252  ndSwap(ndHeap<dItem, dKey>::m_pool[(index - 1) >> 1], ndHeap<dItem, dKey>::m_pool[index]);
253  index = (index - 1) >> 1;
254  }
255 
256  while ((2 * index + 1) < ndHeap<dItem, dKey>::m_curCount)
257  {
258  ndInt32 i0 = 2 * index + 1;
259  ndInt32 i1 = 2 * index + 2;
261  {
262  i0 = (ndHeap<dItem, dKey>::m_pool[i0].m_key > ndHeap<dItem, dKey>::m_pool[i1].m_key) ? i0 : i1;
263  if (ndHeap<dItem, dKey>::m_pool[i0].m_key <= ndHeap<dItem, dKey>::m_pool[index].m_key)
264  {
265  break;
266  }
268  index = i0;
269  }
270  else
271  {
272  if (ndHeap<dItem, dKey>::m_pool[i0].m_key > ndHeap<dItem, dKey>::m_pool[index].m_key)
273  {
275  }
276  index = i0;
277  }
278  }
279  ndAssert(SanityCheck());
280 }
281 
282 template <class dItem, class dKey>
284 {
285  ndInt32 count = ndHeap<dItem, dKey>::m_curCount;
286  for (ndInt32 i = 1; i < count; ++i)
287  {
288  dKey key(ndHeap<dItem, dKey>::m_pool[0].m_key);
289  dItem obj(ndHeap<dItem, dKey>::m_pool[0].m_obj);
290 
291  Pop();
292 
295  }
296 
298  for (ndInt32 i = 0; i < count / 2; ++i)
299  {
300  dKey key(ndHeap<dItem, dKey>::m_pool[i].m_key);
301  dItem obj(ndHeap<dItem, dKey>::m_pool[i].m_obj);
302 
303  ndHeap<dItem, dKey>::m_pool[i].m_key = ndHeap<dItem, dKey>::m_pool[count - i - 1].m_key;
304  ndHeap<dItem, dKey>::m_pool[i].m_obj = ndHeap<dItem, dKey>::m_pool[count - i - 1].m_obj;
305 
306  ndHeap<dItem, dKey>::m_pool[count - i - 1].m_key = key;
307  ndHeap<dItem, dKey>::m_pool[count - i - 1].m_obj = obj;
308  }
309  ndAssert(SanityCheck());
310 }
311 
312 // *****************************************
313 //
314 // two typical instances of heaps, up and down.
315 //
316 // *****************************************
317 template <class dKey>
319 {
320  public:
321  ndDownHeapCompare(dKey key)
322  :m_key(key)
323  {
324  }
325 
326  bool operator> (const ndDownHeapCompare<dKey>& key) const
327  {
328  return m_key > key.m_key;
329  }
330 
331  bool operator< (const ndDownHeapCompare<dKey>& key) const
332  {
333  return m_key < key.m_key;
334  }
335 
336  bool operator<= (const ndDownHeapCompare<dKey>& key) const
337  {
338  return m_key <= key.m_key;
339  }
340 
341  dKey m_key;
342 };
343 
344 template <class dItem, class dKey>
345 class ndDownHeap : public ndHeap<dItem, ndDownHeapCompare<dKey>>
346 {
347  public:
348  ndDownHeap(ndInt32 maxElements)
350  {
351  }
352 
353  ndDownHeap(const void* const buffer, ndInt32 sizeInBytes)
354  :ndHeap<dItem, ndDownHeapCompare<dKey>>(buffer, sizeInBytes)
355  {
356  }
357 
358  dKey Value(ndInt32 i = 0) const
359  {
360  const ndDownHeapCompare<dKey> key(ndHeap<dItem, ndDownHeapCompare<dKey>>::Value(i));
361  return key.m_key;
362  }
363 };
364 
365 template <class dKey>
367 {
368  public:
369  ndUpHeapCompare(dKey key)
370  :m_key(key)
371  {
372  }
373 
374  bool operator> (const ndUpHeapCompare<dKey>& key) const
375  {
376  return m_key < key.m_key;
377  }
378 
379  bool operator< (const ndUpHeapCompare<dKey>& key) const
380  {
381  return m_key > key.m_key;
382  }
383 
384  bool operator<= (const ndUpHeapCompare<dKey>& key) const
385  {
386  return m_key >= key.m_key;
387  }
388 
389  dKey m_key;
390 };
391 
392 template <class dItem, class dKey>
393 class ndUpHeap : public ndHeap<dItem, ndUpHeapCompare<dKey>>
394 {
395  public:
396  ndUpHeap(ndInt32 maxElements)
398  {
399  }
400 
401  ndUpHeap(const void* const buffer, ndInt32 sizeInBytes)
402  :ndHeap<dItem, ndUpHeapCompare<dKey>>(buffer, sizeInBytes)
403  {
404  }
405 
406  dKey Value(ndInt32 i = 0) const
407  {
408  const ndUpHeapCompare<dKey> key(ndHeap<dItem, ndUpHeapCompare<dKey>>::Value(i));
409  return key.m_key;
410  }
411 };
412 
413 #endif
ndClassAlloc
Base class for providing memory allocation for all other engine classes.
Definition: ndClassAlloc.h:30
ndHeap
Definition: ndHeap.h:40
ndHeap::dRecord
Definition: ndHeap.h:63
ndDownHeap
Definition: ndHeap.h:346
ndMemory
Definition: ndMemory.h:32
ndDownHeapCompare
Definition: ndHeap.h:319
ndUpHeapCompare
Definition: ndHeap.h:367
ndUpHeap
Definition: ndHeap.h:394
ndMemory::Free
static D_CORE_API void Free(void *const ptr)
Destroy a memory buffer previously allocated by Malloc.
Definition: ndMemory.cpp:61