| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284 |
- //--------------------------------------------------------------------------------------
- // File: D3DXGlobal.h
- //
- // Direct3D 11 Effects helper defines and data structures
- //
- // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
- // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
- // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
- // PARTICULAR PURPOSE.
- //
- // Copyright (c) Microsoft Corporation. All rights reserved.
- //
- // http://go.microsoft.com/fwlink/p/?LinkId=271568
- //--------------------------------------------------------------------------------------
- #pragma once
- #include <assert.h>
- #include <string.h>
- namespace D3DX11Debug
- {
- // Helper sets a D3D resource name string (used by PIX and debug layer leak reporting).
- inline void SetDebugObjectName(_In_ ID3D11DeviceChild* resource, _In_z_ const char *name )
- {
- #if !defined(NO_D3D11_DEBUG_NAME) && ( defined(_DEBUG) || defined(PROFILE) )
- resource->SetPrivateData( WKPDID_D3DDebugObjectName, static_cast<UINT>(strlen(name)), name );
- #else
- UNREFERENCED_PARAMETER(resource);
- UNREFERENCED_PARAMETER(name);
- #endif
- }
- template<UINT TNameLength>
- inline void SetDebugObjectName(_In_ ID3D11DeviceChild* resource, _In_z_ const char (&name)[TNameLength])
- {
- #if !defined(NO_D3D11_DEBUG_NAME) && ( defined(_DEBUG) || defined(PROFILE) )
- resource->SetPrivateData(WKPDID_D3DDebugObjectName, TNameLength - 1, name);
- #else
- UNREFERENCED_PARAMETER(resource);
- UNREFERENCED_PARAMETER(name);
- #endif
- }
- }
- using namespace D3DX11Debug;
- #define SAFE_RELEASE(p) { if (p) { (p)->Release(); (p) = nullptr; } }
- #define SAFE_ADDREF(p) { if (p) { (p)->AddRef(); } }
- #define SAFE_DELETE_ARRAY(p) { delete [](p); p = nullptr; }
- #define SAFE_DELETE(p) { delete (p); p = nullptr; }
- #if FXDEBUG
- #define __BREAK_ON_FAIL { __debugbreak(); }
- #else
- #define __BREAK_ON_FAIL
- #endif
- #define VA(x, action) { hr = (x); if (FAILED(hr)) { action; __BREAK_ON_FAIL; return hr; } }
- #define VNA(x,action) { if (!(x)) { action; __BREAK_ON_FAIL; hr = E_OUTOFMEMORY; goto lExit; } }
- #define VBA(x,action) { if (!(x)) { action; __BREAK_ON_FAIL; hr = E_FAIL; goto lExit; } }
- #define VHA(x,action) { hr = (x); if (FAILED(hr)) { action; __BREAK_ON_FAIL; goto lExit; } }
- #define V(x) { VA (x, 0) }
- #define VN(x) { VNA(x, 0) }
- #define VB(x) { VBA(x, 0) }
- #define VH(x) { VHA(x, 0) }
- #define VBD(x,str) { VBA(x, DPF(1,str)) }
- #define VHD(x,str) { VHA(x, DPF(1,str)) }
- #define VEASSERT(x) { hr = (x); if (FAILED(hr)) { __BREAK_ON_FAIL; assert(!#x); goto lExit; } }
- #define VNASSERT(x) { if (!(x)) { __BREAK_ON_FAIL; assert(!#x); hr = E_OUTOFMEMORY; goto lExit; } }
- #define D3DX11FLTASSIGN(a,b) { *reinterpret_cast< UINT32* >(&(a)) = *reinterpret_cast< UINT32* >(&(b)); }
- // Preferred data alignment -- must be a power of 2!
- static const uint32_t c_DataAlignment = sizeof(UINT_PTR);
- inline uint32_t AlignToPowerOf2(uint32_t Value, uint32_t Alignment)
- {
- assert((Alignment & (Alignment - 1)) == 0);
- // to align to 2^N, add 2^N - 1 and AND with all but lowest N bits set
- _Analysis_assume_(Alignment > 0 && Value < MAXDWORD - Alignment);
- return (Value + Alignment - 1) & (~(Alignment - 1));
- }
- inline void * AlignToPowerOf2(void *pValue, UINT_PTR Alignment)
- {
- assert((Alignment & (Alignment - 1)) == 0);
- // to align to 2^N, add 2^N - 1 and AND with all but lowest N bits set
- return (void *)(((UINT_PTR)pValue + Alignment - 1) & (~((UINT_PTR)Alignment - 1)));
- }
- namespace D3DX11Core
- {
- //////////////////////////////////////////////////////////////////////////
- // CMemoryStream - A class to simplify reading binary data
- //////////////////////////////////////////////////////////////////////////
- class CMemoryStream
- {
- uint8_t *m_pData;
- size_t m_cbData;
- size_t m_readPtr;
- public:
- HRESULT SetData(_In_reads_bytes_(size) const void *pData, _In_ size_t size);
- HRESULT Read(_Out_ uint32_t *pUint);
- HRESULT Read(_Outptr_result_buffer_(size) void **ppData, _In_ size_t size);
- HRESULT Read(_Outptr_ LPCSTR *ppString);
- HRESULT ReadAtOffset(_In_ size_t offset, _In_ size_t size, _Outptr_result_buffer_(size) void **ppData);
- HRESULT ReadAtOffset(_In_ size_t offset, _Outptr_result_z_ LPCSTR *ppString);
- size_t GetPosition();
- HRESULT Seek(_In_ size_t offset);
- CMemoryStream();
- ~CMemoryStream();
- };
- }
- #if defined(_DEBUG) && !defined(_M_X64)
- namespace D3DX11Debug
- {
- // This variable indicates how many ticks to go before rolling over
- // all of the timer variables in the FX system.
- // It is read from the system registry in debug builds; in retail the high bit is simply tested.
- _declspec(selectany) unsigned int g_TimerRolloverCount = 0x80000000;
- }
- #endif // _DEBUG && !_M_X64
- //////////////////////////////////////////////////////////////////////////
- // CEffectVector - A vector implementation
- //////////////////////////////////////////////////////////////////////////
- template<class T> class CEffectVector
- {
- protected:
- #if _DEBUG
- T *m_pCastData; // makes debugging easier to have a casted version of the data
- #endif // _DEBUG
- uint8_t *m_pData;
- uint32_t m_MaxSize;
- uint32_t m_CurSize;
- HRESULT Grow()
- {
- return Reserve(m_CurSize + 1);
- }
- HRESULT Reserve(_In_ uint32_t DesiredSize)
- {
- if (DesiredSize > m_MaxSize)
- {
- uint8_t *pNewData;
- uint32_t newSize = std::max(m_MaxSize * 2, DesiredSize);
- if (newSize < 16)
- newSize = 16;
- if ((newSize < m_MaxSize) || (newSize < m_CurSize) || (newSize >= UINT_MAX / sizeof(T)))
- {
- m_hLastError = E_OUTOFMEMORY;
- return m_hLastError;
- }
- pNewData = new uint8_t[newSize * sizeof(T)];
- if (pNewData == nullptr)
- {
- m_hLastError = E_OUTOFMEMORY;
- return m_hLastError;
- }
- if (m_pData)
- {
- memcpy(pNewData, m_pData, m_CurSize * sizeof(T));
- delete []m_pData;
- }
- m_pData = pNewData;
- m_MaxSize = newSize;
- }
- #if _DEBUG
- m_pCastData = (T*) m_pData;
- #endif // _DEBUG
- return S_OK;
- }
- public:
- HRESULT m_hLastError;
- CEffectVector<T>() : m_hLastError(S_OK), m_pData(nullptr), m_CurSize(0), m_MaxSize(0)
- {
- #if _DEBUG
- m_pCastData = nullptr;
- #endif // _DEBUG
- }
- ~CEffectVector<T>()
- {
- Clear();
- }
- // cleanly swaps two vectors -- useful for when you want
- // to reallocate a vector and copy data over, then swap them back
- void SwapVector(_Out_ CEffectVector<T> &vOther)
- {
- uint8_t tempData[sizeof(*this)];
- memcpy(tempData, this, sizeof(*this));
- memcpy(this, &vOther, sizeof(*this));
- memcpy(&vOther, tempData, sizeof(*this));
- }
- HRESULT CopyFrom(_In_ const CEffectVector<T> &vOther)
- {
- HRESULT hr = S_OK;
- Clear();
- VN( m_pData = new uint8_t[vOther.m_MaxSize * sizeof(T)] );
-
- m_CurSize = vOther.m_CurSize;
- m_MaxSize = vOther.m_MaxSize;
- m_hLastError = vOther.m_hLastError;
- for (size_t i = 0; i < m_CurSize; ++ i)
- {
- ((T*)m_pData)[i] = ((T*)vOther.m_pData)[i];
- }
- lExit:
- #if _DEBUG
- m_pCastData = (T*) m_pData;
- #endif // _DEBUG
- return hr;
- }
- void Clear()
- {
- Empty();
- SAFE_DELETE_ARRAY(m_pData);
- m_MaxSize = 0;
- #if _DEBUG
- m_pCastData = nullptr;
- #endif // _DEBUG
- }
- void ClearWithoutDestructor()
- {
- m_CurSize = 0;
- m_hLastError = S_OK;
- SAFE_DELETE_ARRAY(m_pData);
- m_MaxSize = 0;
- #if _DEBUG
- m_pCastData = nullptr;
- #endif // _DEBUG
- }
- void Empty()
- {
-
- // manually invoke destructor on all elements
- for (size_t i = 0; i < m_CurSize; ++ i)
- {
- ((T*)m_pData + i)->~T();
- }
- m_CurSize = 0;
- m_hLastError = S_OK;
- }
- T* Add()
- {
- if (FAILED(Grow()))
- return nullptr;
- // placement new
- return new((T*)m_pData + (m_CurSize ++)) T;
- }
- T* AddRange(_In_ uint32_t count)
- {
- if (m_CurSize + count < m_CurSize)
- {
- m_hLastError = E_OUTOFMEMORY;
- return nullptr;
- }
- if (FAILED(Reserve(m_CurSize + count)))
- return nullptr;
- T *pData = (T*)m_pData + m_CurSize;
- for (size_t i = 0; i < count; ++ i)
- {
- new(pData + i) T;
- }
- m_CurSize += count;
- return pData;
- }
- HRESULT Add(_In_ const T& var)
- {
- if (FAILED(Grow()))
- return m_hLastError;
- memcpy((T*)m_pData + m_CurSize, &var, sizeof(T));
- m_CurSize++;
- return S_OK;
- }
- HRESULT AddRange(_In_reads_(count) const T *pVar, _In_ uint32_t count)
- {
- if (m_CurSize + count < m_CurSize)
- {
- m_hLastError = E_OUTOFMEMORY;
- return m_hLastError;
- }
- if (FAILED(Reserve(m_CurSize + count)))
- return m_hLastError;
- memcpy((T*)m_pData + m_CurSize, pVar, count * sizeof(T));
- m_CurSize += count;
- return S_OK;
- }
- HRESULT Insert(_In_ const T& var, _In_ uint32_t index)
- {
- assert(index < m_CurSize);
-
- if (FAILED(Grow()))
- return m_hLastError;
- memmove((T*)m_pData + index + 1, (T*)m_pData + index, (m_CurSize - index) * sizeof(T));
- memcpy((T*)m_pData + index, &var, sizeof(T));
- m_CurSize++;
- return S_OK;
- }
- HRESULT InsertRange(_In_reads_(count) const T *pVar, _In_ uint32_t index, _In_ uint32_t count)
- {
- assert(index < m_CurSize);
-
- if (m_CurSize + count < m_CurSize)
- {
- m_hLastError = E_OUTOFMEMORY;
- return m_hLastError;
- }
- if (FAILED(Reserve(m_CurSize + count)))
- return m_hLastError;
- memmove((T*)m_pData + index + count, (T*)m_pData + index, (m_CurSize - index) * sizeof(T));
- memcpy((T*)m_pData + index, pVar, count * sizeof(T));
- m_CurSize += count;
- return S_OK;
- }
- inline T& operator[](_In_ size_t index)
- {
- assert(index < m_CurSize);
- return ((T*)m_pData)[index];
- }
- // Deletes element at index and shifts all other values down
- void Delete(_In_ uint32_t index)
- {
- assert(index < m_CurSize);
- -- m_CurSize;
- memmove((T*)m_pData + index, (T*)m_pData + index + 1, (m_CurSize - index) * sizeof(T));
- }
- // Deletes element at index and moves the last element into its place
- void QuickDelete(_In_ uint32_t index)
- {
- assert(index < m_CurSize);
- -- m_CurSize;
- memcpy((T*)m_pData + index, (T*)m_pData + m_CurSize, sizeof(T));
- }
- inline uint32_t GetSize() const
- {
- return m_CurSize;
- }
- inline T* GetData() const
- {
- return (T*)m_pData;
- }
- uint32_t FindIndexOf(_In_ const void *pEntry) const
- {
- for (size_t i = 0; i < m_CurSize; ++ i)
- {
- if (((T*)m_pData + i) == pEntry)
- return i;
- }
- return -1;
- }
- void Sort(int (__cdecl *pfnCompare)(const void *pElem1, const void *pElem2))
- {
- qsort(m_pData, m_CurSize, sizeof(T), pfnCompare);
- }
- };
- //////////////////////////////////////////////////////////////////////////
- // CEffectVectorOwner - implements a vector of ptrs to objects. The vector owns the objects.
- //////////////////////////////////////////////////////////////////////////
- template<class T> class CEffectVectorOwner : public CEffectVector<T*>
- {
- public:
- ~CEffectVectorOwner<T>()
- {
- Clear();
- for (size_t i=0; i<m_CurSize; i++)
- SAFE_DELETE(((T**)m_pData)[i]);
- SAFE_DELETE_ARRAY(m_pData);
- }
- void Clear()
- {
- Empty();
- SAFE_DELETE_ARRAY(m_pData);
- m_MaxSize = 0;
- }
- void Empty()
- {
- // manually invoke destructor on all elements
- for (size_t i = 0; i < m_CurSize; ++ i)
- {
- SAFE_DELETE(((T**)m_pData)[i]);
- }
- m_CurSize = 0;
- m_hLastError = S_OK;
- }
- void Delete(_In_ uint32_t index)
- {
- assert(index < m_CurSize);
- SAFE_DELETE(((T**)m_pData)[index]);
- CEffectVector<T*>::Delete(index);
- }
- };
- //////////////////////////////////////////////////////////////////////////
- // Checked uint32_t, uint64_t
- // Use CheckedNumber only with uint32_t and uint64_t
- //////////////////////////////////////////////////////////////////////////
- template <class T, T MaxValue> class CheckedNumber
- {
- T m_Value;
- bool m_bValid;
- public:
- CheckedNumber<T, MaxValue>() : m_Value(0), m_bValid(true)
- {
- }
- CheckedNumber<T, MaxValue>(const T &value) : m_Value(value), m_bValid(true)
- {
- }
- CheckedNumber<T, MaxValue>(const CheckedNumber<T, MaxValue> &value) : m_bValid(value.m_bValid), m_Value(value.m_Value)
- {
- }
- CheckedNumber<T, MaxValue> &operator+(const CheckedNumber<T, MaxValue> &other)
- {
- CheckedNumber<T, MaxValue> Res(*this);
- return Res+=other;
- }
- CheckedNumber<T, MaxValue> &operator+=(const CheckedNumber<T, MaxValue> &other)
- {
- if (!other.m_bValid)
- {
- m_bValid = false;
- }
- else
- {
- m_Value += other.m_Value;
- if (m_Value < other.m_Value)
- m_bValid = false;
- }
- return *this;
- }
- CheckedNumber<T, MaxValue> &operator*(const CheckedNumber<T, MaxValue> &other)
- {
- CheckedNumber<T, MaxValue> Res(*this);
- return Res*=other;
- }
- CheckedNumber<T, MaxValue> &operator*=(const CheckedNumber<T, MaxValue> &other)
- {
- if (!other.m_bValid)
- {
- m_bValid = false;
- }
- else
- {
- if (other.m_Value != 0)
- {
- if (m_Value > MaxValue / other.m_Value)
- {
- m_bValid = false;
- }
- }
- m_Value *= other.m_Value;
- }
- return *this;
- }
- HRESULT GetValue(_Out_ T *pValue)
- {
- if (!m_bValid)
- {
- *pValue = uint32_t(-1);
- return E_FAIL;
- }
- *pValue = m_Value;
- return S_OK;
- }
- };
- typedef CheckedNumber<uint32_t, _UI32_MAX> CCheckedDword;
- typedef CheckedNumber<uint64_t, _UI64_MAX> CCheckedDword64;
- //////////////////////////////////////////////////////////////////////////
- // Data Block Store - A linked list of allocations
- //////////////////////////////////////////////////////////////////////////
- class CDataBlock
- {
- protected:
- uint32_t m_size;
- uint32_t m_maxSize;
- uint8_t *m_pData;
- CDataBlock *m_pNext;
- bool m_IsAligned; // Whether or not to align the data to c_DataAlignment
- public:
- // AddData appends an existing use buffer to the data block
- HRESULT AddData(_In_reads_bytes_(bufferSize) const void *pNewData, _In_ uint32_t bufferSize, _Outptr_ CDataBlock **ppBlock);
- // Allocate reserves bufferSize bytes of contiguous memory and returns a pointer to the user
- _Success_(return != nullptr)
- void* Allocate(_In_ uint32_t bufferSize, _Outptr_ CDataBlock **ppBlock);
- void EnableAlignment();
- CDataBlock();
- ~CDataBlock();
- friend class CDataBlockStore;
- };
- class CDataBlockStore
- {
- protected:
- CDataBlock *m_pFirst;
- CDataBlock *m_pLast;
- uint32_t m_Size;
- uint32_t m_Offset; // m_Offset gets added to offsets returned from AddData & AddString. Use this to set a global for the entire string block
- bool m_IsAligned; // Whether or not to align the data to c_DataAlignment
- public:
- #if _DEBUG
- uint32_t m_cAllocations;
- #endif
- public:
- HRESULT AddString(_In_z_ LPCSTR pString, _Inout_ uint32_t *pOffset);
- // Writes a null-terminated string to buffer
- HRESULT AddData(_In_reads_bytes_(bufferSize) const void *pNewData, _In_ uint32_t bufferSize, _Inout_ uint32_t *pOffset);
- // Writes data block to buffer
- // Memory allocator support
- void* Allocate(_In_ uint32_t bufferSize);
- uint32_t GetSize();
- void EnableAlignment();
- CDataBlockStore();
- ~CDataBlockStore();
- };
- // Custom allocator that uses CDataBlockStore
- // The trick is that we never free, so we don't have to keep as much state around
- // Use PRIVATENEW in CEffectLoader
- inline void* __cdecl operator new(_In_ size_t s, _In_ CDataBlockStore &pAllocator)
- {
- #ifdef _M_X64
- assert( s <= 0xffffffff );
- #endif
- return pAllocator.Allocate( (uint32_t)s );
- }
- inline void __cdecl operator delete(_In_opt_ void* p, _In_ CDataBlockStore &pAllocator)
- {
- UNREFERENCED_PARAMETER(p);
- UNREFERENCED_PARAMETER(pAllocator);
- }
- //////////////////////////////////////////////////////////////////////////
- // Hash table
- //////////////////////////////////////////////////////////////////////////
- #define HASH_MIX(a,b,c) \
- { \
- a -= b; a -= c; a ^= (c>>13); \
- b -= c; b -= a; b ^= (a<<8); \
- c -= a; c -= b; c ^= (b>>13); \
- a -= b; a -= c; a ^= (c>>12); \
- b -= c; b -= a; b ^= (a<<16); \
- c -= a; c -= b; c ^= (b>>5); \
- a -= b; a -= c; a ^= (c>>3); \
- b -= c; b -= a; b ^= (a<<10); \
- c -= a; c -= b; c ^= (b>>15); \
- }
- static uint32_t ComputeHash(_In_reads_bytes_(cbToHash) const uint8_t *pb, _In_ uint32_t cbToHash)
- {
- uint32_t cbLeft = cbToHash;
- uint32_t a;
- uint32_t b;
- a = b = 0x9e3779b9; // the golden ratio; an arbitrary value
- uint32_t c = 0;
- while (cbLeft >= 12)
- {
- const uint32_t *pdw = reinterpret_cast<const uint32_t *>(pb);
- a += pdw[0];
- b += pdw[1];
- c += pdw[2];
- HASH_MIX(a,b,c);
- pb += 12;
- cbLeft -= 12;
- }
- c += cbToHash;
- switch(cbLeft) // all the case statements fall through
- {
- case 11: c+=((uint32_t) pb[10] << 24);
- case 10: c+=((uint32_t) pb[9] << 16);
- case 9 : c+=((uint32_t) pb[8] << 8);
- // the first byte of c is reserved for the length
- case 8 : b+=((uint32_t) pb[7] << 24);
- case 7 : b+=((uint32_t) pb[6] << 16);
- case 6 : b+=((uint32_t) pb[5] << 8);
- case 5 : b+=pb[4];
- case 4 : a+=((uint32_t) pb[3] << 24);
- case 3 : a+=((uint32_t) pb[2] << 16);
- case 2 : a+=((uint32_t) pb[1] << 8);
- case 1 : a+=pb[0];
- }
- HASH_MIX(a,b,c);
- return c;
- }
- static uint32_t ComputeHashLower(_In_reads_bytes_(cbToHash) const uint8_t *pb, _In_ uint32_t cbToHash)
- {
- uint32_t cbLeft = cbToHash;
- uint32_t a;
- uint32_t b;
- a = b = 0x9e3779b9; // the golden ratio; an arbitrary value
- uint32_t c = 0;
- while (cbLeft >= 12)
- {
- uint8_t pbT[12];
- for( size_t i = 0; i < 12; i++ )
- pbT[i] = (uint8_t)tolower(pb[i]);
- uint32_t *pdw = reinterpret_cast<uint32_t *>(pbT);
- a += pdw[0];
- b += pdw[1];
- c += pdw[2];
- HASH_MIX(a,b,c);
- pb += 12;
- cbLeft -= 12;
- }
- c += cbToHash;
- uint8_t pbT[12];
- for( size_t i = 0; i < cbLeft; i++ )
- pbT[i] = (uint8_t)tolower(pb[i]);
- switch(cbLeft) // all the case statements fall through
- {
- case 11: c+=((uint32_t) pbT[10] << 24);
- case 10: c+=((uint32_t) pbT[9] << 16);
- case 9 : c+=((uint32_t) pbT[8] << 8);
- // the first byte of c is reserved for the length
- case 8 : b+=((uint32_t) pbT[7] << 24);
- case 7 : b+=((uint32_t) pbT[6] << 16);
- case 6 : b+=((uint32_t) pbT[5] << 8);
- case 5 : b+=pbT[4];
- case 4 : a+=((uint32_t) pbT[3] << 24);
- case 3 : a+=((uint32_t) pbT[2] << 16);
- case 2 : a+=((uint32_t) pbT[1] << 8);
- case 1 : a+=pbT[0];
- }
- HASH_MIX(a,b,c);
- return c;
- }
- static uint32_t ComputeHash(_In_z_ LPCSTR pString)
- {
- return ComputeHash(reinterpret_cast<const uint8_t*>(pString), (uint32_t)strlen(pString));
- }
- // 1) these numbers are prime
- // 2) each is slightly less than double the last
- // 4) each is roughly in between two powers of 2;
- // (2^n hash table sizes are VERY BAD; they effectively truncate your
- // precision down to the n least significant bits of the hash)
- static const uint32_t c_PrimeSizes[] =
- {
- 11,
- 23,
- 53,
- 97,
- 193,
- 389,
- 769,
- 1543,
- 3079,
- 6151,
- 12289,
- 24593,
- 49157,
- 98317,
- 196613,
- 393241,
- 786433,
- 1572869,
- 3145739,
- 6291469,
- 12582917,
- 25165843,
- 50331653,
- 100663319,
- 201326611,
- 402653189,
- 805306457,
- 1610612741,
- };
- template<typename T, bool (*pfnIsEqual)(const T &Data1, const T &Data2)>
- class CEffectHashTable
- {
- protected:
- struct SHashEntry
- {
- uint32_t Hash;
- T Data;
- SHashEntry *pNext;
- };
- // Array of hash entries
- SHashEntry **m_rgpHashEntries;
- uint32_t m_NumHashSlots;
- uint32_t m_NumEntries;
- bool m_bOwnHashEntryArray;
- public:
- class CIterator
- {
- friend class CEffectHashTable;
- protected:
- SHashEntry **ppHashSlot;
- SHashEntry *pHashEntry;
- public:
- T GetData()
- {
- assert(pHashEntry != 0);
- _Analysis_assume_(pHashEntry != 0);
- return pHashEntry->Data;
- }
- uint32_t GetHash()
- {
- assert(pHashEntry != 0);
- _Analysis_assume_(pHashEntry != 0);
- return pHashEntry->Hash;
- }
- };
- CEffectHashTable() : m_rgpHashEntries(nullptr), m_NumHashSlots(0), m_NumEntries(0), m_bOwnHashEntryArray(false)
- {
- }
- HRESULT Initialize(_In_ const CEffectHashTable *pOther)
- {
- HRESULT hr = S_OK;
- SHashEntry **rgpNewHashEntries = nullptr;
- uint32_t valuesMigrated = 0;
- uint32_t actualSize;
- Cleanup();
- actualSize = pOther->m_NumHashSlots;
- VN( rgpNewHashEntries = new SHashEntry*[actualSize] );
- ZeroMemory(rgpNewHashEntries, sizeof(SHashEntry*) * actualSize);
- // Expensive operation: rebuild the hash table
- CIterator iter, nextIter;
- pOther->GetFirstEntry(&iter);
- while (!pOther->PastEnd(&iter))
- {
- uint32_t index = iter.GetHash() % actualSize;
- // we need to advance to the next element
- // before we seize control of this element and move
- // it to the new table
- nextIter = iter;
- pOther->GetNextEntry(&nextIter);
- // seize this hash entry, migrate it to the new table
- SHashEntry *pNewEntry;
- VN( pNewEntry = new SHashEntry );
-
- pNewEntry->pNext = rgpNewHashEntries[index];
- pNewEntry->Data = iter.pHashEntry->Data;
- pNewEntry->Hash = iter.pHashEntry->Hash;
- rgpNewHashEntries[index] = pNewEntry;
- iter = nextIter;
- ++ valuesMigrated;
- }
- assert(valuesMigrated == pOther->m_NumEntries);
- m_rgpHashEntries = rgpNewHashEntries;
- m_NumHashSlots = actualSize;
- m_NumEntries = pOther->m_NumEntries;
- m_bOwnHashEntryArray = true;
- rgpNewHashEntries = nullptr;
- lExit:
- SAFE_DELETE_ARRAY( rgpNewHashEntries );
- return hr;
- }
- protected:
- void CleanArray()
- {
- if (m_bOwnHashEntryArray)
- {
- SAFE_DELETE_ARRAY(m_rgpHashEntries);
- m_bOwnHashEntryArray = false;
- }
- }
- public:
- void Cleanup()
- {
- for (size_t i = 0; i < m_NumHashSlots; ++ i)
- {
- SHashEntry *pCurrentEntry = m_rgpHashEntries[i];
- SHashEntry *pTempEntry;
- while (nullptr != pCurrentEntry)
- {
- pTempEntry = pCurrentEntry->pNext;
- SAFE_DELETE(pCurrentEntry);
- pCurrentEntry = pTempEntry;
- -- m_NumEntries;
- }
- }
- CleanArray();
- m_NumHashSlots = 0;
- assert(m_NumEntries == 0);
- }
- ~CEffectHashTable()
- {
- Cleanup();
- }
- static uint32_t GetNextHashTableSize(_In_ uint32_t DesiredSize)
- {
- // figure out the next logical size to use
- for (size_t i = 0; i < _countof(c_PrimeSizes); ++i )
- {
- if (c_PrimeSizes[i] >= DesiredSize)
- {
- return c_PrimeSizes[i];
- }
- }
- return DesiredSize;
- }
-
- // O(n) function
- // Grows to the next suitable size (based off of the prime number table)
- // DesiredSize is merely a suggestion
- HRESULT Grow(_In_ uint32_t DesiredSize,
- _In_ uint32_t ProvidedArraySize = 0,
- _In_reads_opt_(ProvidedArraySize) void** ProvidedArray = nullptr,
- _In_ bool OwnProvidedArray = false)
- {
- HRESULT hr = S_OK;
- SHashEntry **rgpNewHashEntries = nullptr;
- uint32_t valuesMigrated = 0;
- uint32_t actualSize;
- VB( DesiredSize > m_NumHashSlots );
- actualSize = GetNextHashTableSize(DesiredSize);
- if (ProvidedArray &&
- ProvidedArraySize >= actualSize)
- {
- rgpNewHashEntries = reinterpret_cast<SHashEntry**>(ProvidedArray);
- }
- else
- {
- OwnProvidedArray = true;
-
- VN( rgpNewHashEntries = new SHashEntry*[actualSize] );
- }
-
- ZeroMemory(rgpNewHashEntries, sizeof(SHashEntry*) * actualSize);
- // Expensive operation: rebuild the hash table
- CIterator iter, nextIter;
- GetFirstEntry(&iter);
- while (!PastEnd(&iter))
- {
- uint32_t index = iter.GetHash() % actualSize;
- // we need to advance to the next element
- // before we seize control of this element and move
- // it to the new table
- nextIter = iter;
- GetNextEntry(&nextIter);
- // seize this hash entry, migrate it to the new table
- iter.pHashEntry->pNext = rgpNewHashEntries[index];
- rgpNewHashEntries[index] = iter.pHashEntry;
- iter = nextIter;
- ++ valuesMigrated;
- }
- assert(valuesMigrated == m_NumEntries);
- CleanArray();
- m_rgpHashEntries = rgpNewHashEntries;
- m_NumHashSlots = actualSize;
- m_bOwnHashEntryArray = OwnProvidedArray;
- lExit:
- return hr;
- }
- HRESULT AutoGrow()
- {
- // arbitrary heuristic -- grow if 1:1
- if (m_NumEntries >= m_NumHashSlots)
- {
- // grows this hash table so that it is roughly 50% full
- return Grow(m_NumEntries * 2 + 1);
- }
- return S_OK;
- }
- #if _DEBUG
- void PrintHashTableStats()
- {
- if (m_NumHashSlots == 0)
- {
- DPF(0, "Uninitialized hash table!");
- return;
- }
-
- float variance = 0.0f;
- float mean = (float)m_NumEntries / (float)m_NumHashSlots;
- uint32_t unusedSlots = 0;
- DPF(0, "Hash table slots: %d, Entries in table: %d", m_NumHashSlots, m_NumEntries);
- for (size_t i = 0; i < m_NumHashSlots; ++ i)
- {
- uint32_t entries = 0;
- SHashEntry *pCurrentEntry = m_rgpHashEntries[i];
- while (nullptr != pCurrentEntry)
- {
- SHashEntry *pCurrentEntry2 = m_rgpHashEntries[i];
-
- // check other hash entries in this slot for hash collisions or duplications
- while (pCurrentEntry2 != pCurrentEntry)
- {
- if (pCurrentEntry->Hash == pCurrentEntry2->Hash)
- {
- if (pfnIsEqual(pCurrentEntry->Data, pCurrentEntry2->Data))
- {
- assert(0);
- DPF(0, "Duplicate entry (identical hash, identical data) found!");
- }
- else
- {
- DPF(0, "Hash collision (hash: %d)", pCurrentEntry->Hash);
- }
- }
- pCurrentEntry2 = pCurrentEntry2->pNext;
- }
- pCurrentEntry = pCurrentEntry->pNext;
- ++ entries;
- }
- if (0 == entries)
- {
- ++ unusedSlots;
- }
-
- // mean must be greater than 0 at this point
- variance += (float)entries * (float)entries / mean;
- }
- variance /= std::max(1.0f, (m_NumHashSlots - 1));
- variance -= (mean * mean);
- DPF(0, "Mean number of entries per slot: %f, Standard deviation: %f, Unused slots; %d", mean, variance, unusedSlots);
- }
- #endif // _DEBUG
- // S_OK if element is found, E_FAIL otherwise
- HRESULT FindValueWithHash(_In_ T Data, _In_ uint32_t Hash, _Out_ CIterator *pIterator)
- {
- assert(m_NumHashSlots > 0);
- uint32_t index = Hash % m_NumHashSlots;
- SHashEntry *pEntry = m_rgpHashEntries[index];
- while (nullptr != pEntry)
- {
- if (Hash == pEntry->Hash && pfnIsEqual(pEntry->Data, Data))
- {
- pIterator->ppHashSlot = m_rgpHashEntries + index;
- pIterator->pHashEntry = pEntry;
- return S_OK;
- }
- pEntry = pEntry->pNext;
- }
- return E_FAIL;
- }
- // S_OK if element is found, E_FAIL otherwise
- HRESULT FindFirstMatchingValue(_In_ uint32_t Hash, _Out_ CIterator *pIterator)
- {
- assert(m_NumHashSlots > 0);
- uint32_t index = Hash % m_NumHashSlots;
- SHashEntry *pEntry = m_rgpHashEntries[index];
- while (nullptr != pEntry)
- {
- if (Hash == pEntry->Hash)
- {
- pIterator->ppHashSlot = m_rgpHashEntries + index;
- pIterator->pHashEntry = pEntry;
- return S_OK;
- }
- pEntry = pEntry->pNext;
- }
- return E_FAIL;
- }
- // Adds data at the specified hash slot without checking for existence
- HRESULT AddValueWithHash(_In_ T Data, _In_ uint32_t Hash)
- {
- HRESULT hr = S_OK;
- assert(m_NumHashSlots > 0);
- SHashEntry *pHashEntry;
- uint32_t index = Hash % m_NumHashSlots;
- VN( pHashEntry = new SHashEntry );
- pHashEntry->pNext = m_rgpHashEntries[index];
- pHashEntry->Data = Data;
- pHashEntry->Hash = Hash;
- m_rgpHashEntries[index] = pHashEntry;
- ++ m_NumEntries;
- lExit:
- return hr;
- }
- // Iterator code:
- //
- // CMyHashTable::CIterator myIt;
- // for (myTable.GetFirstEntry(&myIt); !myTable.PastEnd(&myIt); myTable.GetNextEntry(&myIt)
- // { myTable.GetData(&myIt); }
- void GetFirstEntry(_Out_ CIterator *pIterator)
- {
- SHashEntry **ppEnd = m_rgpHashEntries + m_NumHashSlots;
- pIterator->ppHashSlot = m_rgpHashEntries;
- while (pIterator->ppHashSlot < ppEnd)
- {
- if (nullptr != *(pIterator->ppHashSlot))
- {
- pIterator->pHashEntry = *(pIterator->ppHashSlot);
- return;
- }
- ++ pIterator->ppHashSlot;
- }
- }
- bool PastEnd(_Inout_ CIterator *pIterator)
- {
- SHashEntry **ppEnd = m_rgpHashEntries + m_NumHashSlots;
- assert(pIterator->ppHashSlot >= m_rgpHashEntries && pIterator->ppHashSlot <= ppEnd);
- return (pIterator->ppHashSlot == ppEnd);
- }
- void GetNextEntry(_Inout_ CIterator *pIterator)
- {
- SHashEntry **ppEnd = m_rgpHashEntries + m_NumHashSlots;
- assert(pIterator->ppHashSlot >= m_rgpHashEntries && pIterator->ppHashSlot <= ppEnd);
- assert(pIterator->pHashEntry != 0);
- _Analysis_assume_(pIterator->pHashEntry != 0);
- pIterator->pHashEntry = pIterator->pHashEntry->pNext;
- if (nullptr != pIterator->pHashEntry)
- {
- return;
- }
- ++ pIterator->ppHashSlot;
- while (pIterator->ppHashSlot < ppEnd)
- {
- pIterator->pHashEntry = *(pIterator->ppHashSlot);
- if (nullptr != pIterator->pHashEntry)
- {
- return;
- }
- ++ pIterator->ppHashSlot;
- }
- // hit the end of the list, ppHashSlot == ppEnd
- }
- void RemoveEntry(_Inout_ CIterator *pIterator)
- {
- SHashEntry *pTemp;
- SHashEntry **ppPrev;
- SHashEntry **ppEnd = m_rgpHashEntries + m_NumHashSlots;
- assert(pIterator && !PastEnd(pIterator));
- ppPrev = pIterator->ppHashSlot;
- pTemp = *ppPrev;
- while (pTemp)
- {
- if (pTemp == pIterator->pHashEntry)
- {
- *ppPrev = pTemp->pNext;
- pIterator->ppHashSlot = ppEnd;
- delete pTemp;
- return;
- }
- ppPrev = &pTemp->pNext;
- pTemp = pTemp->pNext;
- }
- // Should never get here
- assert(0);
- }
- };
- // Allocates the hash slots on the regular heap (since the
- // hash table can grow), but all hash entries are allocated on
- // a private heap
- template<typename T, bool (*pfnIsEqual)(const T &Data1, const T &Data2)>
- class CEffectHashTableWithPrivateHeap : public CEffectHashTable<T, pfnIsEqual>
- {
- protected:
- CDataBlockStore *m_pPrivateHeap;
- public:
- CEffectHashTableWithPrivateHeap()
- {
- m_pPrivateHeap = nullptr;
- }
- void Cleanup()
- {
- CleanArray();
- m_NumHashSlots = 0;
- m_NumEntries = 0;
- }
- ~CEffectHashTableWithPrivateHeap()
- {
- Cleanup();
- }
- // Call this only once
- void SetPrivateHeap(_In_ CDataBlockStore *pPrivateHeap)
- {
- assert(nullptr == m_pPrivateHeap);
- m_pPrivateHeap = pPrivateHeap;
- }
- // Adds data at the specified hash slot without checking for existence
- HRESULT AddValueWithHash(_In_ T Data, _In_ uint32_t Hash)
- {
- HRESULT hr = S_OK;
- assert(m_pPrivateHeap);
- _Analysis_assume_(m_pPrivateHeap);
- assert(m_NumHashSlots > 0);
- SHashEntry *pHashEntry;
- uint32_t index = Hash % m_NumHashSlots;
- VN( pHashEntry = new(*m_pPrivateHeap) SHashEntry );
- pHashEntry->pNext = m_rgpHashEntries[index];
- pHashEntry->Data = Data;
- pHashEntry->Hash = Hash;
- m_rgpHashEntries[index] = pHashEntry;
- ++ m_NumEntries;
- lExit:
- return hr;
- }
- };
|