Initial git commit
This commit is contained in:
374
Source/WDL/heapbuf.h
Normal file
374
Source/WDL/heapbuf.h
Normal file
@ -0,0 +1,374 @@
|
||||
/*
|
||||
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_
|
Reference in New Issue
Block a user