You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

375 lines
10KB

  1. /*
  2. WDL - heapbuf.h
  3. Copyright (C) 2005 and later Cockos Incorporated
  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. /*
  19. This file provides the interface and implementation for WDL_HeapBuf, a simple
  20. malloc() wrapper for resizeable blocks.
  21. Also in this file is WDL_TypedBuf which is a templated version WDL_HeapBuf
  22. that manages type and type-size.
  23. */
  24. #ifndef _WDL_HEAPBUF_H_
  25. #define _WDL_HEAPBUF_H_
  26. #ifndef WDL_HEAPBUF_IMPL_ONLY
  27. #ifdef WDL_HEAPBUF_TRACE
  28. #include <windows.h>
  29. #define WDL_HEAPBUF_TRACEPARM(x) ,(x)
  30. #else
  31. #define WDL_HEAPBUF_TRACEPARM(x)
  32. #endif
  33. #include "wdltypes.h"
  34. class WDL_HeapBuf
  35. {
  36. public:
  37. // interface
  38. #ifdef WDL_HEAPBUF_INTF_ONLY
  39. void *Resize(int newsize, bool resizedown=true);
  40. void CopyFrom(const WDL_HeapBuf *hb, bool exactCopyOfConfig=false);
  41. #endif
  42. void *Get() const { return m_size?m_buf:NULL; }
  43. int GetSize() const { return m_size; }
  44. void *GetAligned(int align) const { return (void *)(((UINT_PTR)Get() + (align-1)) & ~(UINT_PTR)(align-1)); }
  45. void SetGranul(int granul) { m_granul = granul; }
  46. int GetGranul() const { return m_granul; }
  47. void *ResizeOK(int newsize, bool resizedown = true) { void *p=Resize(newsize, resizedown); return GetSize() == newsize ? p : NULL; }
  48. WDL_HeapBuf(const WDL_HeapBuf &cp)
  49. {
  50. m_buf=0;
  51. CopyFrom(&cp,true);
  52. }
  53. WDL_HeapBuf &operator=(const WDL_HeapBuf &cp)
  54. {
  55. CopyFrom(&cp,false);
  56. return *this;
  57. }
  58. #ifndef WDL_HEAPBUF_TRACE
  59. explicit WDL_HeapBuf(int granul=4096) : m_buf(NULL), m_alloc(0), m_size(0), m_granul(granul)
  60. {
  61. }
  62. ~WDL_HeapBuf()
  63. {
  64. free(m_buf);
  65. }
  66. #else
  67. explicit WDL_HeapBuf(int granul=4096, const char *tracetype="WDL_HeapBuf"
  68. ) : m_buf(NULL), m_alloc(0), m_size(0), m_granul(granul)
  69. {
  70. m_tracetype = tracetype;
  71. char tmp[512];
  72. wsprintf(tmp,"WDL_HeapBuf: created type: %s granul=%d\n",tracetype,granul);
  73. OutputDebugString(tmp);
  74. }
  75. ~WDL_HeapBuf()
  76. {
  77. char tmp[512];
  78. wsprintf(tmp,"WDL_HeapBuf: destroying type: %s (alloc=%d, size=%d)\n",m_tracetype,m_alloc,m_size);
  79. OutputDebugString(tmp);
  80. free(m_buf);
  81. }
  82. #endif
  83. #endif // !WDL_HEAPBUF_IMPL_ONLY
  84. // implementation bits
  85. #ifndef WDL_HEAPBUF_INTF_ONLY
  86. #ifdef WDL_HEAPBUF_IMPL_ONLY
  87. void *WDL_HeapBuf::Resize(int newsize, bool resizedown)
  88. #else
  89. void *Resize(int newsize, bool resizedown=true)
  90. #endif
  91. {
  92. if (newsize<0) newsize=0;
  93. #ifdef DEBUG_TIGHT_ALLOC // horribly slow, do not use for release builds
  94. if (newsize == m_size) return m_buf;
  95. int a = newsize;
  96. if (a > m_size) a=m_size;
  97. void *newbuf = newsize ? malloc(newsize) : 0;
  98. if (!newbuf && newsize)
  99. {
  100. #ifdef WDL_HEAPBUF_ONMALLOCFAIL
  101. WDL_HEAPBUF_ONMALLOCFAIL(newsize)
  102. #endif
  103. return m_buf;
  104. }
  105. if (newbuf&&m_buf) memcpy(newbuf,m_buf,a);
  106. m_size=m_alloc=newsize;
  107. free(m_buf);
  108. return m_buf=newbuf;
  109. #endif
  110. if (newsize!=m_size || (resizedown && newsize < m_alloc/2))
  111. {
  112. int resizedown_under = 0;
  113. if (resizedown && newsize < m_size)
  114. {
  115. // shrinking buffer: only shrink if allocation decreases to min(alloc/2, alloc-granul*4) or 0
  116. resizedown_under = m_alloc - (m_granul<<2);
  117. if (resizedown_under > m_alloc/2) resizedown_under = m_alloc/2;
  118. if (resizedown_under < 1) resizedown_under=1;
  119. }
  120. if (newsize > m_alloc || newsize < resizedown_under)
  121. {
  122. int granul=newsize/2;
  123. int newalloc;
  124. if (granul < m_granul) granul=m_granul;
  125. if (newsize<1) newalloc=0;
  126. else if (m_granul<4096) newalloc=newsize+granul;
  127. else
  128. {
  129. granul &= ~4095;
  130. if (granul< 4096) granul=4096;
  131. else if (granul>4*1024*1024) granul=4*1024*1024;
  132. newalloc = ((newsize + granul + 96)&~4095)-96;
  133. }
  134. if (newalloc != m_alloc)
  135. {
  136. #ifdef WDL_HEAPBUF_TRACE
  137. char tmp[512];
  138. wsprintf(tmp,"WDL_HeapBuf: type %s realloc(%d) from %d\n",m_tracetype,newalloc,m_alloc);
  139. OutputDebugString(tmp);
  140. #endif
  141. if (newalloc <= 0)
  142. {
  143. free(m_buf);
  144. m_buf=0;
  145. m_alloc=0;
  146. m_size=0;
  147. return 0;
  148. }
  149. void *nbuf=realloc(m_buf,newalloc);
  150. if (!nbuf)
  151. {
  152. if (!(nbuf=malloc(newalloc)))
  153. {
  154. #ifdef WDL_HEAPBUF_ONMALLOCFAIL
  155. WDL_HEAPBUF_ONMALLOCFAIL(newalloc);
  156. #endif
  157. return m_size?m_buf:0; // failed, do not resize
  158. }
  159. if (m_buf)
  160. {
  161. int sz=newsize<m_size?newsize:m_size;
  162. if (sz>0) memcpy(nbuf,m_buf,sz);
  163. free(m_buf);
  164. }
  165. }
  166. m_buf=nbuf;
  167. m_alloc=newalloc;
  168. } // alloc size change
  169. } // need size up or down
  170. m_size=newsize;
  171. } // size change
  172. return m_size?m_buf:0;
  173. }
  174. #ifdef WDL_HEAPBUF_IMPL_ONLY
  175. void WDL_HeapBuf::CopyFrom(const WDL_HeapBuf *hb, bool exactCopyOfConfig)
  176. #else
  177. void CopyFrom(const WDL_HeapBuf *hb, bool exactCopyOfConfig=false)
  178. #endif
  179. {
  180. if (exactCopyOfConfig) // copy all settings
  181. {
  182. free(m_buf);
  183. #ifdef WDL_HEAPBUF_TRACE
  184. m_tracetype = hb->m_tracetype;
  185. #endif
  186. m_granul = hb->m_granul;
  187. m_size=m_alloc=0;
  188. m_buf=hb->m_buf && hb->m_alloc>0 ? malloc(m_alloc = hb->m_alloc) : NULL;
  189. #ifdef WDL_HEAPBUF_ONMALLOCFAIL
  190. if (!m_buf && m_alloc) { WDL_HEAPBUF_ONMALLOCFAIL(m_alloc) } ;
  191. #endif
  192. if (m_buf) memcpy(m_buf,hb->m_buf,m_size = hb->m_size);
  193. else m_alloc=0;
  194. }
  195. else // copy just the data + size
  196. {
  197. const int newsz=hb->GetSize();
  198. Resize(newsz,true);
  199. if (GetSize()!=newsz) Resize(0);
  200. else memcpy(Get(),hb->Get(),newsz);
  201. }
  202. }
  203. #endif // ! WDL_HEAPBUF_INTF_ONLY
  204. #ifndef WDL_HEAPBUF_IMPL_ONLY
  205. private:
  206. void *m_buf;
  207. int m_alloc;
  208. int m_size;
  209. int m_granul;
  210. #if defined(_WIN64) || defined(__LP64__)
  211. public:
  212. int ___pad; // keep size 8 byte aligned
  213. #endif
  214. #ifdef WDL_HEAPBUF_TRACE
  215. const char *m_tracetype;
  216. #endif
  217. };
  218. template<class PTRTYPE> class WDL_TypedBuf
  219. {
  220. public:
  221. PTRTYPE *Get() const { return (PTRTYPE *) m_hb.Get(); }
  222. int GetSize() const { return m_hb.GetSize()/(unsigned int)sizeof(PTRTYPE); }
  223. PTRTYPE *Resize(int newsize, bool resizedown = true) { return (PTRTYPE *)m_hb.Resize(newsize*sizeof(PTRTYPE),resizedown); }
  224. PTRTYPE *ResizeOK(int newsize, bool resizedown = true) { return (PTRTYPE *)m_hb.ResizeOK(newsize*sizeof(PTRTYPE), resizedown); }
  225. PTRTYPE *GetAligned(int align) const { return (PTRTYPE *) m_hb.GetAligned(align); }
  226. PTRTYPE *Add(PTRTYPE val)
  227. {
  228. const int sz=GetSize();
  229. PTRTYPE* p=ResizeOK(sz+1,false);
  230. if (p)
  231. {
  232. p[sz]=val;
  233. return p+sz;
  234. }
  235. return NULL;
  236. }
  237. PTRTYPE *Add(const PTRTYPE *buf, int bufsz)
  238. {
  239. if (bufsz>0)
  240. {
  241. const int sz=GetSize();
  242. PTRTYPE* p=ResizeOK(sz+bufsz,false);
  243. if (p)
  244. {
  245. p+=sz;
  246. if (buf) memcpy(p,buf,bufsz*sizeof(PTRTYPE));
  247. else memset(p,0,bufsz*sizeof(PTRTYPE));
  248. return p;
  249. }
  250. }
  251. return NULL;
  252. }
  253. PTRTYPE *Set(const PTRTYPE *buf, int bufsz)
  254. {
  255. if (bufsz>=0)
  256. {
  257. PTRTYPE* p=ResizeOK(bufsz,false);
  258. if (p)
  259. {
  260. if (buf) memcpy(p,buf,bufsz*sizeof(PTRTYPE));
  261. else memset(p,0,bufsz*sizeof(PTRTYPE));
  262. return p;
  263. }
  264. }
  265. return NULL;
  266. }
  267. PTRTYPE* Insert(PTRTYPE val, int idx)
  268. {
  269. const int sz=GetSize();
  270. if (idx >= 0 && idx <= sz)
  271. {
  272. PTRTYPE* p=ResizeOK(sz+1,false);
  273. if (p)
  274. {
  275. memmove(p+idx+1, p+idx, (sz-idx)*sizeof(PTRTYPE));
  276. p[idx]=val;
  277. return p+idx;
  278. }
  279. }
  280. return NULL;
  281. }
  282. void Delete(int idx)
  283. {
  284. PTRTYPE* p=Get();
  285. const int sz=GetSize();
  286. if (idx >= 0 && idx < sz)
  287. {
  288. memmove(p+idx, p+idx+1, (sz-idx-1)*sizeof(PTRTYPE));
  289. Resize(sz-1,false);
  290. }
  291. }
  292. void SetGranul(int gran) { m_hb.SetGranul(gran); }
  293. int Find(PTRTYPE val) const
  294. {
  295. const PTRTYPE* p=Get();
  296. const int sz=GetSize();
  297. int i;
  298. for (i=0; i < sz; ++i) if (p[i] == val) return i;
  299. return -1;
  300. }
  301. #ifndef WDL_HEAPBUF_TRACE
  302. explicit WDL_TypedBuf(int granul=4096) : m_hb(granul) { }
  303. #else
  304. explicit WDL_TypedBuf(int granul=4096, const char *tracetype="WDL_TypedBuf") : m_hb(granul WDL_HEAPBUF_TRACEPARM(tracetype)) { }
  305. #endif
  306. ~WDL_TypedBuf()
  307. {
  308. }
  309. PTRTYPE* begin() const { return static_cast<PTRTYPE*>(m_hb.Get()); }
  310. PTRTYPE* end() const
  311. {
  312. PTRTYPE* temp = static_cast<PTRTYPE*>(m_hb.Get());
  313. return temp + m_hb.GetSize() / sizeof(PTRTYPE);
  314. }
  315. WDL_HeapBuf *GetHeapBuf() { return &m_hb; }
  316. const WDL_HeapBuf *GetHeapBuf() const { return &m_hb; }
  317. private:
  318. WDL_HeapBuf m_hb;
  319. };
  320. #endif // ! WDL_HEAPBUF_IMPL_ONLY
  321. #endif // _WDL_HEAPBUF_H_