Merge pull request #110 from tesselode/fixes
[wdl/wdl-ol.git] / WDL / heapbuf.h
blob226845beaaccea177778dca866a6ac0ba2939a99
1 /*
2 WDL - heapbuf.h
3 Copyright (C) 2005 and later Cockos Incorporated
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
25 This file provides the interface and implementation for WDL_HeapBuf, a simple
26 malloc() wrapper for resizeable blocks.
28 Also in this file is WDL_TypedBuf which is a templated version WDL_HeapBuf
29 that manages type and type-size.
33 #ifndef _WDL_HEAPBUF_H_
34 #define _WDL_HEAPBUF_H_
36 #ifndef WDL_HEAPBUF_IMPL_ONLY
38 #ifdef WDL_HEAPBUF_TRACE
39 #include <windows.h>
40 #define WDL_HEAPBUF_TRACEPARM(x) ,(x)
41 #else
42 #define WDL_HEAPBUF_TRACEPARM(x)
43 #endif
45 #include "wdltypes.h"
47 class WDL_HeapBuf
49 public:
50 // interface
51 #ifdef WDL_HEAPBUF_INTF_ONLY
52 void *Resize(int newsize, bool resizedown=true);
53 void CopyFrom(const WDL_HeapBuf *hb, bool exactCopyOfConfig=false);
54 #endif
55 void *Get() const { return m_size?m_buf:NULL; }
56 int GetSize() const { return m_size; }
57 void *GetAligned(int align) const { return (void *)(((UINT_PTR)Get() + (align-1)) & ~(UINT_PTR)(align-1)); }
59 void SetGranul(int granul) { m_granul = granul; }
60 int GetGranul() const { return m_granul; }
62 void *ResizeOK(int newsize, bool resizedown = true) { void *p=Resize(newsize, resizedown); return GetSize() == newsize ? p : NULL; }
64 WDL_HeapBuf(const WDL_HeapBuf &cp)
66 m_buf=0;
67 CopyFrom(&cp,true);
69 WDL_HeapBuf &operator=(const WDL_HeapBuf &cp)
71 CopyFrom(&cp,false);
72 return *this;
77 #ifndef WDL_HEAPBUF_TRACE
78 explicit WDL_HeapBuf(int granul=4096) : m_buf(NULL), m_alloc(0), m_size(0), m_granul(granul)
81 ~WDL_HeapBuf()
83 free(m_buf);
85 #else
86 explicit WDL_HeapBuf(int granul=4096, const char *tracetype="WDL_HeapBuf"
87 ) : m_buf(NULL), m_alloc(0), m_size(0), m_granul(granul)
89 m_tracetype = tracetype;
90 char tmp[512];
91 wsprintf(tmp,"WDL_HeapBuf: created type: %s granul=%d\n",tracetype,granul);
92 OutputDebugString(tmp);
94 ~WDL_HeapBuf()
96 char tmp[512];
97 wsprintf(tmp,"WDL_HeapBuf: destroying type: %s (alloc=%d, size=%d)\n",m_tracetype,m_alloc,m_size);
98 OutputDebugString(tmp);
99 free(m_buf);
101 #endif
103 #endif // !WDL_HEAPBUF_IMPL_ONLY
105 // implementation bits
106 #ifndef WDL_HEAPBUF_INTF_ONLY
107 #ifdef WDL_HEAPBUF_IMPL_ONLY
108 void *WDL_HeapBuf::Resize(int newsize, bool resizedown)
109 #else
110 void *Resize(int newsize, bool resizedown=true)
111 #endif
113 if (newsize<0) newsize=0;
114 #ifdef DEBUG_TIGHT_ALLOC // horribly slow, do not use for release builds
115 if (newsize == m_size) return m_buf;
117 int a = newsize;
118 if (a > m_size) a=m_size;
119 void *newbuf = newsize ? malloc(newsize) : 0;
120 if (!newbuf && newsize)
122 #ifdef WDL_HEAPBUF_ONMALLOCFAIL
123 WDL_HEAPBUF_ONMALLOCFAIL(newsize)
124 #endif
125 return m_buf;
127 if (newbuf&&m_buf) memcpy(newbuf,m_buf,a);
128 m_size=m_alloc=newsize;
129 free(m_buf);
130 return m_buf=newbuf;
131 #endif
133 if (newsize!=m_size || (resizedown && newsize < m_alloc/2))
135 int resizedown_under = 0;
136 if (resizedown && newsize < m_size)
138 // shrinking buffer: only shrink if allocation decreases to min(alloc/2, alloc-granul*4) or 0
139 resizedown_under = m_alloc - (m_granul<<2);
140 if (resizedown_under > m_alloc/2) resizedown_under = m_alloc/2;
141 if (resizedown_under < 1) resizedown_under=1;
144 if (newsize > m_alloc || newsize < resizedown_under)
146 int granul=newsize/2;
147 int newalloc;
148 if (granul < m_granul) granul=m_granul;
150 if (newsize<1) newalloc=0;
151 else if (m_granul<4096) newalloc=newsize+granul;
152 else
154 granul &= ~4095;
155 if (granul< 4096) granul=4096;
156 else if (granul>4*1024*1024) granul=4*1024*1024;
157 newalloc = ((newsize + granul + 96)&~4095)-96;
160 if (newalloc != m_alloc)
163 #ifdef WDL_HEAPBUF_TRACE
164 char tmp[512];
165 wsprintf(tmp,"WDL_HeapBuf: type %s realloc(%d) from %d\n",m_tracetype,newalloc,m_alloc);
166 OutputDebugString(tmp);
167 #endif
168 if (newalloc <= 0)
170 free(m_buf);
171 m_buf=0;
172 m_alloc=0;
173 m_size=0;
174 return 0;
176 void *nbuf=realloc(m_buf,newalloc);
177 if (!nbuf)
179 if (!(nbuf=malloc(newalloc)))
181 #ifdef WDL_HEAPBUF_ONMALLOCFAIL
182 WDL_HEAPBUF_ONMALLOCFAIL(newalloc);
183 #endif
184 return m_size?m_buf:0; // failed, do not resize
187 if (m_buf)
189 int sz=newsize<m_size?newsize:m_size;
190 if (sz>0) memcpy(nbuf,m_buf,sz);
191 free(m_buf);
195 m_buf=nbuf;
196 m_alloc=newalloc;
197 } // alloc size change
198 } // need size up or down
199 m_size=newsize;
200 } // size change
201 return m_size?m_buf:0;
204 #ifdef WDL_HEAPBUF_IMPL_ONLY
205 void WDL_HeapBuf::CopyFrom(const WDL_HeapBuf *hb, bool exactCopyOfConfig)
206 #else
207 void CopyFrom(const WDL_HeapBuf *hb, bool exactCopyOfConfig=false)
208 #endif
210 if (exactCopyOfConfig) // copy all settings
212 free(m_buf);
214 #ifdef WDL_HEAPBUF_TRACE
215 m_tracetype = hb->m_tracetype;
216 #endif
217 m_granul = hb->m_granul;
219 m_size=m_alloc=0;
220 m_buf=hb->m_buf && hb->m_alloc>0 ? malloc(m_alloc = hb->m_alloc) : NULL;
221 #ifdef WDL_HEAPBUF_ONMALLOCFAIL
222 if (!m_buf && m_alloc) { WDL_HEAPBUF_ONMALLOCFAIL(m_alloc) } ;
223 #endif
224 if (m_buf) memcpy(m_buf,hb->m_buf,m_size = hb->m_size);
225 else m_alloc=0;
227 else // copy just the data + size
229 const int newsz=hb->GetSize();
230 Resize(newsz,true);
231 if (GetSize()!=newsz) Resize(0);
232 else memcpy(Get(),hb->Get(),newsz);
236 #endif // ! WDL_HEAPBUF_INTF_ONLY
238 #ifndef WDL_HEAPBUF_IMPL_ONLY
240 private:
241 void *m_buf;
242 int m_alloc;
243 int m_size;
244 int m_granul;
246 #if defined(_WIN64) || defined(__LP64__)
247 public:
248 int ___pad; // keep size 8 byte aligned
249 #endif
251 #ifdef WDL_HEAPBUF_TRACE
252 const char *m_tracetype;
253 #endif
257 template<class PTRTYPE> class WDL_TypedBuf
259 public:
260 PTRTYPE *Get() const { return (PTRTYPE *) m_hb.Get(); }
261 int GetSize() const { return m_hb.GetSize()/(unsigned int)sizeof(PTRTYPE); }
263 PTRTYPE *Resize(int newsize, bool resizedown = true) { return (PTRTYPE *)m_hb.Resize(newsize*sizeof(PTRTYPE),resizedown); }
264 PTRTYPE *ResizeOK(int newsize, bool resizedown = true) { return (PTRTYPE *)m_hb.ResizeOK(newsize*sizeof(PTRTYPE), resizedown); }
266 PTRTYPE *GetAligned(int align) const { return (PTRTYPE *) m_hb.GetAligned(align); }
268 PTRTYPE *Add(PTRTYPE val)
270 const int sz=GetSize();
271 PTRTYPE* p=ResizeOK(sz+1,false);
272 if (p)
274 p[sz]=val;
275 return p+sz;
277 return NULL;
279 PTRTYPE *Add(const PTRTYPE *buf, int bufsz)
281 if (bufsz>0)
283 const int sz=GetSize();
284 PTRTYPE* p=ResizeOK(sz+bufsz,false);
285 if (p)
287 p+=sz;
288 if (buf) memcpy(p,buf,bufsz*sizeof(PTRTYPE));
289 else memset(p,0,bufsz*sizeof(PTRTYPE));
290 return p;
293 return NULL;
295 PTRTYPE *Set(const PTRTYPE *buf, int bufsz)
297 if (bufsz>=0)
299 PTRTYPE* p=ResizeOK(bufsz,false);
300 if (p)
302 if (buf) memcpy(p,buf,bufsz*sizeof(PTRTYPE));
303 else memset(p,0,bufsz*sizeof(PTRTYPE));
304 return p;
307 return NULL;
309 PTRTYPE* Insert(PTRTYPE val, int idx)
311 const int sz=GetSize();
312 if (idx >= 0 && idx <= sz)
314 PTRTYPE* p=ResizeOK(sz+1,false);
315 if (p)
317 memmove(p+idx+1, p+idx, (sz-idx)*sizeof(PTRTYPE));
318 p[idx]=val;
319 return p+idx;
322 return NULL;
325 void Delete(int idx)
327 PTRTYPE* p=Get();
328 const int sz=GetSize();
329 if (idx >= 0 && idx < sz)
331 memmove(p+idx, p+idx+1, (sz-idx-1)*sizeof(PTRTYPE));
332 Resize(sz-1,false);
336 void SetGranul(int gran) { m_hb.SetGranul(gran); }
338 int Find(PTRTYPE val) const
340 const PTRTYPE* p=Get();
341 const int sz=GetSize();
342 int i;
343 for (i=0; i < sz; ++i) if (p[i] == val) return i;
344 return -1;
347 #ifndef WDL_HEAPBUF_TRACE
348 explicit WDL_TypedBuf(int granul=4096) : m_hb(granul) { }
349 #else
350 explicit WDL_TypedBuf(int granul=4096, const char *tracetype="WDL_TypedBuf") : m_hb(granul WDL_HEAPBUF_TRACEPARM(tracetype)) { }
351 #endif
352 ~WDL_TypedBuf()
356 WDL_HeapBuf *GetHeapBuf() { return &m_hb; }
357 const WDL_HeapBuf *GetHeapBuf() const { return &m_hb; }
359 private:
360 WDL_HeapBuf m_hb;
363 #endif // ! WDL_HEAPBUF_IMPL_ONLY
365 #endif // _WDL_HEAPBUF_H_