Gray C++ Libraries  0.0.2
A set of C++ libraries for MSVC, GNU on Windows, WinCE, Linux
cHeap.h
Go to the documentation of this file.
1 //
5 //
6 
7 #ifndef _INC_cHeap_H
8 #define _INC_cHeap_H
9 #ifndef NO_PRAGMA_ONCE
10 #pragma once
11 #endif
12 
13 #include "cMem.h"
14 #include "cDebugAssert.h"
15 #include "cUnitTestDecl.h"
16 
17 // #define USE_HEAP_STATS // Debug total allocation stats.
18 
19 namespace Gray
20 {
21  struct GRAYCORE_LINK cHeap // static class
22  {
27 
28  enum FILL_TYPE
29  {
32  FILL_AllocStack = 0xCC,
33  FILL_Alloc = 0xCD,
34  FILL_Freed = 0xDD,
35 
36 #if (_MSC_VER<1400)
37  FILL_AlignTail = 0xBD,
38 #else
39  FILL_AlignTail = 0xED,
40 #endif
41  FILL_UnusedStack = 0xFE,
42  FILL_Prefix = 0xFD,
43  };
44 
45  static const size_t k_ALLOC_MAX = 0x1000000;
46 
48 #ifdef USE_HEAP_STATS
49  static size_t sm_nAllocTotalBytes;
50 #endif
51 
52  static UINT64 GRAYCALL get_PhysTotal(); // For process/machine
53  static UINT64 GRAYCALL get_PhysAvail();
54 
55  static void GRAYCALL Init(int nFlags = 0);
56  static bool GRAYCALL Check();
57  static size_t GRAYCALL GetSize(const void* pData) noexcept;
58  static bool GRAYCALL IsValidHeap(const void* pData) noexcept;
59 
60  static inline bool IsCorruptHeap(const void* pData) noexcept
61  {
64  if (pData == nullptr) // nullptr is not corrupt.
65  return false;
66  return !IsValidHeap(pData);
67  }
68  static bool GRAYCALL IsValidInside(const void* pData, ptrdiff_t index) noexcept;
69 
70  static void* GRAYCALL AllocPtr(size_t nSize);
71 
72  static inline void* AllocPtr(size_t nSize, const void* pDataInit)
73  {
75  void* pData = AllocPtr(nSize);
76  if (pData != nullptr && pDataInit != nullptr)
77  {
78  cMem::Copy(pData, pDataInit, nSize);
79  }
80  return pData;
81  }
82  static void GRAYCALL FreePtr(void* pData);
83  static void* GRAYCALL ReAllocPtr(void* pData, size_t nSize);
84 
86  };
87 
88  struct GRAYCORE_LINK cHeapAlign : public cHeap // static
89  {
95  typedef cHeap SUPER_t;
96 
97 #if defined(_MSC_VER) && (_MSC_VER >= 1300)
98  static const size_t k_SizeGap = 4;
99  static const size_t k_SizeAlignMax = 128; // max reasonable size for alignment.
100 
101  struct CATTR_PACKED cHeapHeader
102  {
107  void* m_pMallocHead; // pointer back to the returned malloc() memory. may point at self !
108 #ifdef _DEBUG
109  BYTE m_TailGap[k_SizeGap];
110 #endif
111  // ASSUME memory block follows this
112  };
113 
114  static const cHeapHeader* GRAYCALL GetHeader(const void* pData) noexcept;
115 
116  static bool GRAYCALL IsAlignedAlloc(const void* pData, size_t iAligned) noexcept;
117  static bool GRAYCALL IsValidHeap(const void* pData) noexcept;
118  static size_t GRAYCALL GetSize(const void* pData) noexcept;
119  static bool GRAYCALL IsValidInside(const void* pData, INT_PTR index) noexcept;
120 
121  static void* GRAYCALL AllocPtr(size_t nSize, size_t iAligned);
122  static void GRAYCALL FreePtr(void* pData);
123 
124 #else
125  // stub these out.
126  static inline bool IsAlignedAlloc(const void* pData, size_t iAligned) noexcept
127  {
128  return false;
129  }
130  static inline bool IsValidHeap(const void* pData) noexcept
131  {
132  return SUPER_t::IsValidHeap(pData);
133  }
134  static inline size_t GetSize(const void* pData) noexcept
135  {
136  return SUPER_t::GetSize(pData);
137  }
138  static inline bool IsValidInside(const void* pData, INT_PTR index) noexcept
139  {
140  return SUPER_t::IsValidInside(pData, index);
141  }
142 
143  static inline void* AllocPtr(size_t nSize, size_t iAligned)
144  {
145  return SUPER_t::AllocPtr(nSize);
146  }
147  static inline void FreePtr(void* pData)
148  {
149  return SUPER_t::FreePtr(pData);
150  }
151 
152 #endif // _MSC_VER
153  };
154 
156  {
160  typedef cHeapBlock THIS_t;
161  typedef cMemBlock SUPER_t;
162 
163  private:
164  explicit cHeapBlock(void* pData)
165  {
167  UNREFERENCED_PARAMETER(pData);
168  ASSERT(0);
169  }
170 
171  public:
172  cHeapBlock() noexcept
173  {
174  DEBUG_CHECK(m_pData == nullptr);
175  DEBUG_CHECK(m_nSize == 0);
176  }
177  cHeapBlock(const THIS_t& ref)
178  {
180  Alloc(ref.m_pData, ref.m_nSize);
181  }
182  cHeapBlock(THIS_t&& ref) noexcept
183  {
185  m_pData = ref.m_pData; ref.m_pData = nullptr;
186  m_nSize = ref.m_nSize; ref.m_nSize = 0;
187  }
188  explicit cHeapBlock(size_t nSize)
189  {
191  Alloc(nSize);
192  }
193  cHeapBlock(const void* pDataCopy, size_t nSize)
194  {
196  Alloc(pDataCopy, nSize);
197  }
199  {
200  cHeap::FreePtr(m_pData); // nullptr is OK/Safe here.
201  }
202 
203  THIS_t& operator = (const THIS_t& ref)
204  {
206  Alloc(ref.m_pData, ref.get_DataSize());
207  return *this;
208  }
209  THIS_t& operator = (THIS_t&& ref)
210  {
212  m_pData = ref.m_pData; ref.m_pData = nullptr;
213  m_nSize = ref.m_nSize; ref.m_nSize = 0;
214  return *this;
215  }
216 
217  bool isValidRead() const noexcept
218  {
223  return cHeap::IsValidHeap(m_pData);
224  }
225  bool isCorrupt() const noexcept
226  {
230  return cHeap::IsCorruptHeap(m_pData);
231  }
232 
233  size_t get_AllocSize() const
234  {
238  ASSERT(!isCorrupt());
239  return cHeap::GetSize(m_pData);
240  }
241  size_t GetHeapStats(OUT ITERATE_t& iAllocCount) const
242  {
244  if (!isValidPtr())
245  return 0;
246  iAllocCount++; // count total allocations used.
247  return get_AllocSize();
248  }
249  void Free()
250  {
251  if (!isValidPtr())
252  return;
253  cHeap::FreePtr(m_pData);
254  SetEmptyBlock();
255  }
256  void FreeSecure()
257  {
258  if (!isValidPtr())
259  return;
260  cMem::ZeroSecure(m_pData, get_DataSize());
261  cHeap::FreePtr(m_pData);
262  SetEmptyBlock(); // m_pData = nullptr
263  }
264 
265  void SetHeapBlock(void* pData, size_t nSize)
266  {
269  m_pData = pData;
270  m_nSize = nSize;
271  }
273  {
275  SetEmptyBlock();
276  }
277  bool Alloc(size_t nSize)
278  {
282  cHeap::FreePtr(m_pData);
283  if (nSize == 0)
284  {
285  m_pData = nullptr;
286  }
287  else
288  {
289  m_pData = cHeap::AllocPtr(nSize);
290  if (!isValidPtr()) // nSize = 0 may be nullptr or not?
291  {
292  return false; // FAILED HRESULT_WIN32_C(ERROR_NOT_ENOUGH_MEMORY)
293  }
294  }
295  m_nSize = nSize;
296  return true; // nullptr is OK for size = 0
297  }
298  bool Alloc(const void* pData, size_t nSize)
299  {
301 
302  ASSERT(pData == nullptr || !this->IsValidPtr(pData)); // NOT from myself ! // Check before Alloc
303  if (!Alloc(nSize))
304  {
305  return false; // FAILED HRESULT_WIN32_C(ERROR_NOT_ENOUGH_MEMORY)
306  }
307  if (pData != nullptr)
308  {
309  cMem::Copy(m_pData, pData, nSize);
310  }
311  return true;
312  }
313  bool ReAlloc(size_t nSize)
314  {
317  if (nSize != m_nSize)
318  {
319  m_pData = cHeap::ReAllocPtr(m_pData, nSize);
320  if (nSize > 0 && !isValidPtr())
321  {
322  return false; // FAILED HRESULT_WIN32_C(ERROR_NOT_ENOUGH_MEMORY)
323  }
324  m_nSize = nSize;
325  }
326  return true;
327  }
328  bool ReAlloc(const void* pData, size_t nSize)
329  {
330  ASSERT(pData == nullptr || !this->IsValidPtr(pData)); // NOT from myself ! // Check before Alloc
331  if (!ReAlloc(nSize))
332  {
333  return false; // FAILED HRESULT_WIN32_C(ERROR_NOT_ENOUGH_MEMORY)
334  }
335  if (pData != nullptr)
336  {
337  cMem::Copy(m_pData, pData, nSize);
338  }
339  return true;
340  }
341 
342  bool ReAllocLazy(size_t iSizeNew)
343  {
346  if (iSizeNew > m_nSize && iSizeNew > get_AllocSize())
347  {
348  if (!ReAlloc(iSizeNew))
349  return false;
350  }
351  m_nSize = iSizeNew;
352  return true;
353  }
354 
355  bool SetCopy(const cHeapBlock& rSrc)
356  {
358  if (&rSrc == this)
359  return true;
360  return Alloc(rSrc.get_Data(), rSrc.get_DataSize());
361  }
362 
363  void* get_Data() const noexcept
364  {
367 #ifdef _DEBUG
368  DEBUG_CHECK(!isCorrupt());
369 #endif
370  return m_pData;
371  }
372  inline BYTE* get_DataBytes() const noexcept
373  {
376  return (BYTE*)get_Data();
377  }
378  inline char* get_DataA() const noexcept
379  {
381  return (char*)get_Data();
382  }
383  inline wchar_t* get_DataW() const noexcept
384  {
386  return (wchar_t*)get_Data();
387  }
388 
389  operator void* () const noexcept
390  {
391  return get_Data();
392  }
393  operator BYTE* () const noexcept
394  {
395  return get_DataBytes(); // for use with []
396  }
397  operator char* () const noexcept
398  {
399  return get_DataA(); // for use with []
400  }
401  };
402 }
403 
404 #endif // _INC_cHeap_H
#define GRAYCORE_LINK
Definition: GrayCore.h:47
#define GRAYCALL
declare calling convention for static functions so everyone knows the arg passing scheme....
Definition: GrayCore.h:36
#define CATTR_PACKED
Definition: GrayCore.h:87
#define UNREFERENCED_PARAMETER(P)
< _WIN32 type thing. get rid of stupid warning.
Definition: SysTypes.h:299
#define ASSERT(exp)
Definition: cDebugAssert.h:87
#define DEBUG_CHECK(exp)
Definition: cDebugAssert.h:90
#define UNITTEST_FRIEND(n)
Define this in the class body to be unit tested. Allow the unit test to access private/protected stuf...
Definition: cUnitTestDecl.h:17
Definition: cHeap.h:156
bool isValidRead() const noexcept
Definition: cHeap.h:217
size_t GetHeapStats(OUT ITERATE_t &iAllocCount) const
Definition: cHeap.h:241
bool ReAllocLazy(size_t iSizeNew)
Definition: cHeap.h:342
wchar_t * get_DataW() const noexcept
Definition: cHeap.h:383
cHeapBlock(const THIS_t &ref)
Definition: cHeap.h:177
bool Alloc(size_t nSize)
Definition: cHeap.h:277
cHeapBlock() noexcept
Definition: cHeap.h:172
char * get_DataA() const noexcept
Definition: cHeap.h:378
cHeapBlock(THIS_t &&ref) noexcept
Definition: cHeap.h:182
bool isCorrupt() const noexcept
Definition: cHeap.h:225
void * get_Data() const noexcept
Definition: cHeap.h:363
bool ReAlloc(const void *pData, size_t nSize)
Definition: cHeap.h:328
cHeapBlock(size_t nSize)
Definition: cHeap.h:188
BYTE * get_DataBytes() const noexcept
Definition: cHeap.h:372
void Free()
Definition: cHeap.h:249
cHeapBlock(const void *pDataCopy, size_t nSize)
Definition: cHeap.h:193
bool Alloc(const void *pData, size_t nSize)
Definition: cHeap.h:298
bool ReAlloc(size_t nSize)
Definition: cHeap.h:313
void FreeSecure()
Definition: cHeap.h:256
void SetHeapBlock(void *pData, size_t nSize)
Definition: cHeap.h:265
bool SetCopy(const cHeapBlock &rSrc)
Definition: cHeap.h:355
~cHeapBlock()
Definition: cHeap.h:198
void DetachHeapBlock()
Definition: cHeap.h:272
size_t get_AllocSize() const
Definition: cHeap.h:233
Definition: cMem.h:311
void * m_pData
Definition: cMem.h:318
size_t get_DataSize() const noexcept
Definition: cMem.h:344
size_t m_nSize
size_t of m_pData in bytes. May be determined at runtime.
Definition: cMem.h:317
< The main namespace for all Core functions.
Definition: GrayCore.cpp:14
int ITERATE_t
like size_t but signed
Definition: Index.h:28
uint16 index
Definition: sample3.cpp:29
Definition: cHeap.h:89
static bool IsValidInside(const void *pData, INT_PTR index) noexcept
Definition: cHeap.h:138
static bool IsValidHeap(const void *pData) noexcept
Definition: cHeap.h:130
static void FreePtr(void *pData)
Definition: cHeap.h:147
static bool IsAlignedAlloc(const void *pData, size_t iAligned) noexcept
Definition: cHeap.h:126
static size_t GetSize(const void *pData) noexcept
Definition: cHeap.h:134
static void * AllocPtr(size_t nSize, size_t iAligned)
Definition: cHeap.h:143
cHeap SUPER_t
Definition: cHeap.h:95
Definition: cHeap.h:22
static void *__stdcall ReAllocPtr(void *pData, size_t nSize)
Definition: cHeap.cpp:158
static void *__stdcall AllocPtr(size_t nSize)
Definition: cHeap.cpp:125
static void * AllocPtr(size_t nSize, const void *pDataInit)
Definition: cHeap.h:72
static void __stdcall FreePtr(void *pData)
Definition: cHeap.cpp:103
static bool IsCorruptHeap(const void *pData) noexcept
Definition: cHeap.h:60
static bool __stdcall IsValidHeap(const void *pData) noexcept
Definition: cHeap.cpp:245
static ITERATE_t sm_nAllocs
count total allocations (i.e. Number of calls to malloc() minus calls to free())
Definition: cHeap.h:47
static size_t __stdcall GetSize(const void *pData) noexcept
Definition: cHeap.cpp:226
FILL_TYPE
Definition: cHeap.h:29
static void Copy(void *pDst, const void *pSrc, size_t nSizeBlock) noexcept
Definition: cMem.h:132
static void ZeroSecure(void *pData, size_t nSizeBlock) noexcept
Definition: cMem.h:110