|
- /*
- WDL - heapbuf.h
- Copyright (C) 2005 and later Cockos Incorporated
-
- This software is provided 'as-is', without any express or implied
- warranty. In no event will the authors be held liable for any damages
- arising from the use of this software.
-
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely, subject to the following restrictions:
-
- 1. The origin of this software must not be misrepresented; you must not
- claim that you wrote the original software. If you use this software
- in a product, an acknowledgment in the product documentation would be
- appreciated but is not required.
- 2. Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original software.
- 3. This notice may not be removed or altered from any source distribution.
-
- */
-
- /*
-
- This file provides the interface and implementation for WDL_HeapBuf, a simple
- malloc() wrapper for resizeable blocks.
-
- Also in this file is WDL_TypedBuf which is a templated version WDL_HeapBuf
- that manages type and type-size.
-
- */
-
- #ifndef _WDL_HEAPBUF_H_
- #define _WDL_HEAPBUF_H_
-
- #ifndef WDL_HEAPBUF_IMPL_ONLY
-
- #ifdef WDL_HEAPBUF_TRACE
- #include <windows.h>
- #define WDL_HEAPBUF_TRACEPARM(x) ,(x)
- #else
- #define WDL_HEAPBUF_TRACEPARM(x)
- #endif
-
- #include "wdltypes.h"
-
- class WDL_HeapBuf
- {
- public:
- // interface
- #ifdef WDL_HEAPBUF_INTF_ONLY
- void *Resize(int newsize, bool resizedown=true);
- void CopyFrom(const WDL_HeapBuf *hb, bool exactCopyOfConfig=false);
- #endif
- void *Get() const { return m_size?m_buf:NULL; }
- int GetSize() const { return m_size; }
- void *GetAligned(int align) const { return (void *)(((UINT_PTR)Get() + (align-1)) & ~(UINT_PTR)(align-1)); }
-
- void SetGranul(int granul) { m_granul = granul; }
- int GetGranul() const { return m_granul; }
-
- void *ResizeOK(int newsize, bool resizedown = true) { void *p=Resize(newsize, resizedown); return GetSize() == newsize ? p : NULL; }
-
- WDL_HeapBuf(const WDL_HeapBuf &cp)
- {
- m_buf=0;
- CopyFrom(&cp,true);
- }
- WDL_HeapBuf &operator=(const WDL_HeapBuf &cp)
- {
- CopyFrom(&cp,false);
- return *this;
- }
-
-
-
- #ifndef WDL_HEAPBUF_TRACE
- explicit WDL_HeapBuf(int granul=4096) : m_buf(NULL), m_alloc(0), m_size(0), m_granul(granul)
- {
- }
- ~WDL_HeapBuf()
- {
- free(m_buf);
- }
- #else
- explicit WDL_HeapBuf(int granul=4096, const char *tracetype="WDL_HeapBuf"
- ) : m_buf(NULL), m_alloc(0), m_size(0), m_granul(granul)
- {
- m_tracetype = tracetype;
- char tmp[512];
- wsprintf(tmp,"WDL_HeapBuf: created type: %s granul=%d\n",tracetype,granul);
- OutputDebugString(tmp);
- }
- ~WDL_HeapBuf()
- {
- char tmp[512];
- wsprintf(tmp,"WDL_HeapBuf: destroying type: %s (alloc=%d, size=%d)\n",m_tracetype,m_alloc,m_size);
- OutputDebugString(tmp);
- free(m_buf);
- }
- #endif
-
- #endif // !WDL_HEAPBUF_IMPL_ONLY
-
- // implementation bits
- #ifndef WDL_HEAPBUF_INTF_ONLY
- #ifdef WDL_HEAPBUF_IMPL_ONLY
- void *WDL_HeapBuf::Resize(int newsize, bool resizedown)
- #else
- void *Resize(int newsize, bool resizedown=true)
- #endif
- {
- if (newsize<0) newsize=0;
- #ifdef DEBUG_TIGHT_ALLOC // horribly slow, do not use for release builds
- if (newsize == m_size) return m_buf;
-
- int a = newsize;
- if (a > m_size) a=m_size;
- void *newbuf = newsize ? malloc(newsize) : 0;
- if (!newbuf && newsize)
- {
- #ifdef WDL_HEAPBUF_ONMALLOCFAIL
- WDL_HEAPBUF_ONMALLOCFAIL(newsize)
- #endif
- return m_buf;
- }
- if (newbuf&&m_buf) memcpy(newbuf,m_buf,a);
- m_size=m_alloc=newsize;
- free(m_buf);
- return m_buf=newbuf;
- #endif
-
- if (newsize!=m_size || (resizedown && newsize < m_alloc/2))
- {
- int resizedown_under = 0;
- if (resizedown && newsize < m_size)
- {
- // shrinking buffer: only shrink if allocation decreases to min(alloc/2, alloc-granul*4) or 0
- resizedown_under = m_alloc - (m_granul<<2);
- if (resizedown_under > m_alloc/2) resizedown_under = m_alloc/2;
- if (resizedown_under < 1) resizedown_under=1;
- }
-
- if (newsize > m_alloc || newsize < resizedown_under)
- {
- int granul=newsize/2;
- int newalloc;
- if (granul < m_granul) granul=m_granul;
-
- if (newsize<1) newalloc=0;
- else if (m_granul<4096) newalloc=newsize+granul;
- else
- {
- granul &= ~4095;
- if (granul< 4096) granul=4096;
- else if (granul>4*1024*1024) granul=4*1024*1024;
- newalloc = ((newsize + granul + 96)&~4095)-96;
- }
-
- if (newalloc != m_alloc)
- {
-
- #ifdef WDL_HEAPBUF_TRACE
- char tmp[512];
- wsprintf(tmp,"WDL_HeapBuf: type %s realloc(%d) from %d\n",m_tracetype,newalloc,m_alloc);
- OutputDebugString(tmp);
- #endif
- if (newalloc <= 0)
- {
- free(m_buf);
- m_buf=0;
- m_alloc=0;
- m_size=0;
- return 0;
- }
- void *nbuf=realloc(m_buf,newalloc);
- if (!nbuf)
- {
- if (!(nbuf=malloc(newalloc)))
- {
- #ifdef WDL_HEAPBUF_ONMALLOCFAIL
- WDL_HEAPBUF_ONMALLOCFAIL(newalloc);
- #endif
- return m_size?m_buf:0; // failed, do not resize
- }
-
- if (m_buf)
- {
- int sz=newsize<m_size?newsize:m_size;
- if (sz>0) memcpy(nbuf,m_buf,sz);
- free(m_buf);
- }
- }
-
- m_buf=nbuf;
- m_alloc=newalloc;
- } // alloc size change
- } // need size up or down
- m_size=newsize;
- } // size change
- return m_size?m_buf:0;
- }
-
- #ifdef WDL_HEAPBUF_IMPL_ONLY
- void WDL_HeapBuf::CopyFrom(const WDL_HeapBuf *hb, bool exactCopyOfConfig)
- #else
- void CopyFrom(const WDL_HeapBuf *hb, bool exactCopyOfConfig=false)
- #endif
- {
- if (exactCopyOfConfig) // copy all settings
- {
- free(m_buf);
-
- #ifdef WDL_HEAPBUF_TRACE
- m_tracetype = hb->m_tracetype;
- #endif
- m_granul = hb->m_granul;
-
- m_size=m_alloc=0;
- m_buf=hb->m_buf && hb->m_alloc>0 ? malloc(m_alloc = hb->m_alloc) : NULL;
- #ifdef WDL_HEAPBUF_ONMALLOCFAIL
- if (!m_buf && m_alloc) { WDL_HEAPBUF_ONMALLOCFAIL(m_alloc) } ;
- #endif
- if (m_buf) memcpy(m_buf,hb->m_buf,m_size = hb->m_size);
- else m_alloc=0;
- }
- else // copy just the data + size
- {
- const int newsz=hb->GetSize();
- Resize(newsz,true);
- if (GetSize()!=newsz) Resize(0);
- else memcpy(Get(),hb->Get(),newsz);
- }
- }
-
- #endif // ! WDL_HEAPBUF_INTF_ONLY
-
- #ifndef WDL_HEAPBUF_IMPL_ONLY
-
- private:
- void *m_buf;
- int m_alloc;
- int m_size;
- int m_granul;
-
- #if defined(_WIN64) || defined(__LP64__)
- public:
- int ___pad; // keep size 8 byte aligned
- #endif
-
- #ifdef WDL_HEAPBUF_TRACE
- const char *m_tracetype;
- #endif
-
- };
-
- template<class PTRTYPE> class WDL_TypedBuf
- {
- public:
- PTRTYPE *Get() const { return (PTRTYPE *) m_hb.Get(); }
- int GetSize() const { return m_hb.GetSize()/(unsigned int)sizeof(PTRTYPE); }
-
- PTRTYPE *Resize(int newsize, bool resizedown = true) { return (PTRTYPE *)m_hb.Resize(newsize*sizeof(PTRTYPE),resizedown); }
- PTRTYPE *ResizeOK(int newsize, bool resizedown = true) { return (PTRTYPE *)m_hb.ResizeOK(newsize*sizeof(PTRTYPE), resizedown); }
-
- PTRTYPE *GetAligned(int align) const { return (PTRTYPE *) m_hb.GetAligned(align); }
-
- PTRTYPE *Add(PTRTYPE val)
- {
- const int sz=GetSize();
- PTRTYPE* p=ResizeOK(sz+1,false);
- if (p)
- {
- p[sz]=val;
- return p+sz;
- }
- return NULL;
- }
- PTRTYPE *Add(const PTRTYPE *buf, int bufsz)
- {
- if (bufsz>0)
- {
- const int sz=GetSize();
- PTRTYPE* p=ResizeOK(sz+bufsz,false);
- if (p)
- {
- p+=sz;
- if (buf) memcpy(p,buf,bufsz*sizeof(PTRTYPE));
- else memset(p,0,bufsz*sizeof(PTRTYPE));
- return p;
- }
- }
- return NULL;
- }
- PTRTYPE *Set(const PTRTYPE *buf, int bufsz)
- {
- if (bufsz>=0)
- {
- PTRTYPE* p=ResizeOK(bufsz,false);
- if (p)
- {
- if (buf) memcpy(p,buf,bufsz*sizeof(PTRTYPE));
- else memset(p,0,bufsz*sizeof(PTRTYPE));
- return p;
- }
- }
- return NULL;
- }
- PTRTYPE* Insert(PTRTYPE val, int idx)
- {
- const int sz=GetSize();
- if (idx >= 0 && idx <= sz)
- {
- PTRTYPE* p=ResizeOK(sz+1,false);
- if (p)
- {
- memmove(p+idx+1, p+idx, (sz-idx)*sizeof(PTRTYPE));
- p[idx]=val;
- return p+idx;
- }
- }
- return NULL;
- }
-
- void Delete(int idx)
- {
- PTRTYPE* p=Get();
- const int sz=GetSize();
- if (idx >= 0 && idx < sz)
- {
- memmove(p+idx, p+idx+1, (sz-idx-1)*sizeof(PTRTYPE));
- Resize(sz-1,false);
- }
- }
-
- void SetGranul(int gran) { m_hb.SetGranul(gran); }
-
- int Find(PTRTYPE val) const
- {
- const PTRTYPE* p=Get();
- const int sz=GetSize();
- int i;
- for (i=0; i < sz; ++i) if (p[i] == val) return i;
- return -1;
- }
-
- #ifndef WDL_HEAPBUF_TRACE
- explicit WDL_TypedBuf(int granul=4096) : m_hb(granul) { }
- #else
- explicit WDL_TypedBuf(int granul=4096, const char *tracetype="WDL_TypedBuf") : m_hb(granul WDL_HEAPBUF_TRACEPARM(tracetype)) { }
- #endif
- ~WDL_TypedBuf()
- {
- }
-
- PTRTYPE* begin() const { return static_cast<PTRTYPE*>(m_hb.Get()); }
- PTRTYPE* end() const
- {
- PTRTYPE* temp = static_cast<PTRTYPE*>(m_hb.Get());
- return temp + m_hb.GetSize() / sizeof(PTRTYPE);
- }
-
-
- WDL_HeapBuf *GetHeapBuf() { return &m_hb; }
- const WDL_HeapBuf *GetHeapBuf() const { return &m_hb; }
-
-
- private:
- WDL_HeapBuf m_hb;
- };
-
- #endif // ! WDL_HEAPBUF_IMPL_ONLY
-
- #endif // _WDL_HEAPBUF_H_
|