raSystem  1.0 bata
d3dxGlobal.h
Go to the documentation of this file.
1 //
3 // Copyright (C) Microsoft Corporation. All Rights Reserved.
4 //
5 // File: D3DXGlobal.h
6 // Content: D3DX11 Effects helper defines and data structures
7 //
9 
10 #pragma once
11 
12 #pragma warning(disable : 4100 4127 4189 4201 4245 4389 4505 4701 4706)
13 
14 namespace D3DX11Debug
15 {
16 }
17 
18 using namespace D3DX11Debug;
19 
20 #include "d3dx11dbg.h"
21 
22 #define SAFE_RELEASE(p) { if (p) { (p)->Release(); (p) = NULL; } }
23 #define SAFE_ADDREF(p) { if (p) { (p)->AddRef(); } }
24 
25 #define SAFE_DELETE_ARRAY(p) { delete [](p); p = NULL; }
26 #define SAFE_DELETE(p) { delete (p); p = NULL; }
27 
28 #if FXDEBUG
29 #define __BREAK_ON_FAIL { __debugbreak(); }
30 #else
31 #define __BREAK_ON_FAIL
32 #endif
33 
34 #define VA(x, action) { hr = (x); if (FAILED(hr)) { action; __BREAK_ON_FAIL; return hr; } }
35 #define VNA(x,action) { if (!(x)) { action; __BREAK_ON_FAIL; hr = E_OUTOFMEMORY; goto lExit; } }
36 #define VBA(x,action) { if (!(x)) { action; __BREAK_ON_FAIL; hr = E_FAIL; goto lExit; } }
37 #define VHA(x,action) { hr = (x); if (FAILED(hr)) { action; __BREAK_ON_FAIL; goto lExit; } }
38 
39 #define V(x) { VA (x, 0) }
40 #define VN(x) { VNA(x, 0) }
41 #define VB(x) { VBA(x, 0) }
42 #define VH(x) { VHA(x, 0) }
43 
44 #define VBD(x,str) { VBA(x, DPF(1,str)) }
45 #define VHD(x,str) { VHA(x, DPF(1,str)) }
46 
47 #define VEASSERT(x) { hr = (x); if (FAILED(hr)) { __BREAK_ON_FAIL; D3DXASSERT(!#x); goto lExit; } }
48 #define VNASSERT(x) { if (!(x)) { __BREAK_ON_FAIL; D3DXASSERT(!#x); hr = E_OUTOFMEMORY; goto lExit; } }
49 
50 #define ANALYSIS_ASSUME(x) { D3DXASSERT(x); __analysis_assume(x); __assume(x); }
51 
52 #define D3DX11FLTASSIGN(a,b) { *reinterpret_cast< UINT32* >(&(a)) = *reinterpret_cast< UINT32* >(&(b)); }
53 
54 // Preferred data alignment -- must be a power of 2!
55 static const UINT c_DataAlignment = sizeof(UINT_PTR);
56 
57 D3DX11INLINE UINT AlignToPowerOf2(UINT Value, UINT Alignment)
58 {
59  D3DXASSERT((Alignment & (Alignment - 1)) == 0);
60  // to align to 2^N, add 2^N - 1 and AND with all but lowest N bits set
61  ANALYSIS_ASSUME(Alignment > 0 && Value < MAXDWORD - Alignment);
62  return (Value + Alignment - 1) & (~(Alignment - 1));
63 }
64 
65 D3DX11INLINE void * AlignToPowerOf2(void *pValue, UINT_PTR Alignment)
66 {
67  D3DXASSERT((Alignment & (Alignment - 1)) == 0);
68  // to align to 2^N, add 2^N - 1 and AND with all but lowest N bits set
69  return (void *)(((UINT_PTR)pValue + Alignment - 1) & (~((UINT_PTR)Alignment - 1)));
70 }
71 
72 
73 // Fast memcpy
74 D3DX11INLINE void dwordMemcpy( __out_bcount(uByteCount) void * __restrict pDest, __in_bcount(uByteCount) CONST void * __restrict pSource, UINT uByteCount)
75 {
76  UINT i;
77  D3DXASSERT(uByteCount % 4 == 0);
78 #ifdef _AMD64_
79  const UINT qwordCount = uByteCount >> 3;
80 
81  __int64* src64 = (__int64*) pSource;
82  __int64* dst64 = (__int64*) pDest;
83 
84  for (i=0; i<(qwordCount & 0x3); i++)
85  {
86  *(dst64) = *(src64);
87  dst64++;
88  src64++;
89  }
90 
91  for (; i<qwordCount; i+= 4)
92  {
93  *(dst64 ) = *(src64 );
94  *(dst64 + 1 ) = *(src64 + 1 );
95  *(dst64 + 2 ) = *(src64 + 2 );
96  *(dst64 + 3 ) = *(src64 + 3 );
97  dst64 += 4;
98  src64 += 4;
99  }
100 
101  ANALYSIS_ASSUME( dst64 - static_cast< __int64* >(pDest) <= uByteCount - 4 );
102  ANALYSIS_ASSUME( src64 - static_cast< const __int64* >(pSource) <= uByteCount - 4 );
103  if( uByteCount & 0x4 )
104  {
105  *((UINT*)dst64) = *((UINT*)src64);
106  }
107 #else
108  const UINT dwordCount = uByteCount >> 2;
109 
110  for (i=0; i<(dwordCount & 0x3); i++)
111  {
112 #pragma prefast(suppress: __WARNING_UNRELATED_LOOP_TERMINATION, "(dwordCount & 03) < dwordCount")
113  ((UINT*)pDest)[i ] = ((UINT*)pSource)[i ];
114  }
115  for (; i<dwordCount; i+= 4)
116  {
117  ((UINT*)pDest)[i ] = ((UINT*)pSource)[i ];
118  ((UINT*)pDest)[i+1] = ((UINT*)pSource)[i+1];
119  ((UINT*)pDest)[i+2] = ((UINT*)pSource)[i+2];
120  ((UINT*)pDest)[i+3] = ((UINT*)pSource)[i+3];
121  }
122 #endif
123 }
124 
125 
126 namespace D3DX11Core
127 {
128 
130 // CMemoryStream - A class to simplify reading binary data
133 {
134  BYTE *m_pData;
135  SIZE_T m_cbData;
136  SIZE_T m_readPtr;
137 
138 public:
139  HRESULT SetData(const void *pData, SIZE_T size);
140 
141  HRESULT Read(UINT *pUint);
142  HRESULT Read(void **ppData, SIZE_T size);
143  HRESULT Read(LPCSTR *ppString);
144 
145  HRESULT ReadAtOffset(SIZE_T offset, SIZE_T size, void **ppData);
146  HRESULT ReadAtOffset(SIZE_T offset, LPCSTR *ppString);
147 
148  SIZE_T GetPosition();
149  HRESULT Seek(SIZE_T offset);
150 
151  CMemoryStream();
152  ~CMemoryStream();
153 };
154 
155 }
156 
157 #if FXDEBUG
158 
159 namespace D3DX11Debug
160 {
161 
162 // This variable indicates how many ticks to go before rolling over
163 // all of the timer variables in the FX system.
164 // It is read from the system registry in debug builds; in retail the high bit is simply tested.
165 
166 _declspec(selectany) unsigned int g_TimerRolloverCount = 0x80000000;
167 }
168 
169 #endif // FXDEBUG
170 
171 
173 // CEffectVector - A vector implementation
175 
176 template<class T> class CEffectVector
177 {
178 protected:
179 #if _DEBUG
180  T *m_pCastData; // makes debugging easier to have a casted version of the data
181 #endif // _DEBUG
182 
183  BYTE *m_pData;
184  UINT m_MaxSize;
185  UINT m_CurSize;
186 
187  HRESULT Grow()
188  {
189  return Reserve(m_CurSize + 1);
190  }
191 
192  HRESULT Reserve(UINT DesiredSize)
193  {
194  if (DesiredSize > m_MaxSize)
195  {
196  BYTE *pNewData;
197  UINT newSize = max(m_MaxSize * 2, DesiredSize);
198 
199  if (newSize < 16)
200  newSize = 16;
201 
202  if ((newSize < m_MaxSize) || (newSize < m_CurSize) || (newSize >= UINT_MAX / sizeof(T)))
203  {
204  m_hLastError = E_OUTOFMEMORY;
205  return m_hLastError;
206  }
207 
208  pNewData = NEW BYTE[newSize * sizeof(T)];
209  if (pNewData == NULL)
210  {
211  m_hLastError = E_OUTOFMEMORY;
212  return m_hLastError;
213  }
214 
215  if (m_pData)
216  {
217  memcpy(pNewData, m_pData, m_CurSize * sizeof(T));
218  delete []m_pData;
219  }
220 
221  m_pData = pNewData;
222  m_MaxSize = newSize;
223  }
224 #if _DEBUG
225  m_pCastData = (T*) m_pData;
226 #endif // _DEBUG
227  return S_OK;
228  }
229 
230 public:
231  HRESULT m_hLastError;
232 
234  {
235  m_hLastError = S_OK;
236 #if _DEBUG
237  m_pCastData = NULL;
238 #endif // _DEBUG
239  m_pData = NULL;
240  m_CurSize = m_MaxSize = 0;
241  }
242 
244  {
245  Clear();
246  }
247 
248  // cleanly swaps two vectors -- useful for when you want
249  // to reallocate a vector and copy data over, then swap them back
251  {
252  BYTE tempData[sizeof(*this)];
253 
254  memcpy(tempData, this, sizeof(*this));
255  memcpy(this, &vOther, sizeof(*this));
256  memcpy(&vOther, tempData, sizeof(*this));
257  }
258 
259  HRESULT CopyFrom(CEffectVector<T> &vOther)
260  {
261  HRESULT hr = S_OK;
262  Clear();
263  VN( m_pData = NEW BYTE[vOther.m_MaxSize * sizeof(T)] );
264 
265  m_CurSize = vOther.m_CurSize;
266  m_MaxSize = vOther.m_MaxSize;
267  m_hLastError = vOther.m_hLastError;
268 
269  UINT i;
270  for (i = 0; i < m_CurSize; ++ i)
271  {
272  ((T*)m_pData)[i] = ((T*)vOther.m_pData)[i];
273  }
274 
275 lExit:
276 
277 #if _DEBUG
278  m_pCastData = (T*) m_pData;
279 #endif // _DEBUG
280 
281  return hr;
282  }
283 
284  void Clear()
285  {
286  Empty();
287  SAFE_DELETE_ARRAY(m_pData);
288  m_MaxSize = 0;
289 #if _DEBUG
290  m_pCastData = NULL;
291 #endif // _DEBUG
292  }
293 
295  {
296  m_CurSize = 0;
297  m_hLastError = S_OK;
298  SAFE_DELETE_ARRAY(m_pData);
299  m_MaxSize = 0;
300 
301 #if _DEBUG
302  m_pCastData = NULL;
303 #endif // _DEBUG
304  }
305 
306  void Empty()
307  {
308  UINT i;
309 
310  // manually invoke destructor on all elements
311  for (i = 0; i < m_CurSize; ++ i)
312  {
313  ((T*)m_pData + i)->~T();
314  }
315  m_CurSize = 0;
316  m_hLastError = S_OK;
317  }
318 
319  T* Add()
320  {
321  if (FAILED(Grow()))
322  return NULL;
323 
324  // placement new
325  return new((T*)m_pData + (m_CurSize ++)) T;
326  }
327 
328  T* AddRange(UINT count)
329  {
330  if (m_CurSize + count < m_CurSize)
331  {
332  m_hLastError = E_OUTOFMEMORY;
333  return NULL;
334  }
335 
336  if (FAILED(Reserve(m_CurSize + count)))
337  return NULL;
338 
339  T *pData = (T*)m_pData + m_CurSize;
340  UINT i;
341  for (i = 0; i < count; ++ i)
342  {
343  new(pData + i) T;
344  }
345  m_CurSize += count;
346  return pData;
347  }
348 
349  HRESULT Add(const T& var)
350  {
351  if (FAILED(Grow()))
352  return m_hLastError;
353 
354  memcpy((T*)m_pData + m_CurSize, &var, sizeof(T));
355  m_CurSize++;
356 
357  return S_OK;
358  }
359 
360  HRESULT AddRange(const T *pVar, UINT count)
361  {
362  if (m_CurSize + count < m_CurSize)
363  {
364  m_hLastError = E_OUTOFMEMORY;
365  return m_hLastError;
366  }
367 
368  if (FAILED(Reserve(m_CurSize + count)))
369  return m_hLastError;
370 
371  memcpy((T*)m_pData + m_CurSize, pVar, count * sizeof(T));
372  m_CurSize += count;
373 
374  return S_OK;
375  }
376 
377  HRESULT Insert(const T& var, UINT index)
378  {
379  D3DXASSERT(index < m_CurSize);
380 
381  if (FAILED(Grow()))
382  return m_hLastError;
383 
384  memmove((T*)m_pData + index + 1, (T*)m_pData + index, (m_CurSize - index) * sizeof(T));
385  memcpy((T*)m_pData + index, &var, sizeof(T));
386  m_CurSize++;
387 
388  return S_OK;
389  }
390 
391  HRESULT InsertRange(const T *pVar, UINT index, UINT count)
392  {
393  D3DXASSERT(index < m_CurSize);
394 
395  if (m_CurSize + count < m_CurSize)
396  {
397  m_hLastError = E_OUTOFMEMORY;
398  return m_hLastError;
399  }
400 
401  if (FAILED(Reserve(m_CurSize + count)))
402  return m_hLastError;
403 
404  memmove((T*)m_pData + index + count, (T*)m_pData + index, (m_CurSize - index) * sizeof(T));
405  memcpy((T*)m_pData + index, pVar, count * sizeof(T));
406  m_CurSize += count;
407 
408  return S_OK;
409  }
410 
411  inline T& operator[](UINT index)
412  {
413  D3DXASSERT(index < m_CurSize);
414  return ((T*)m_pData)[index];
415  }
416 
417  // Deletes element at index and shifts all other values down
418  void Delete(UINT index)
419  {
420  D3DXASSERT(index < m_CurSize);
421 
422  -- m_CurSize;
423  memmove((T*)m_pData + index, (T*)m_pData + index + 1, (m_CurSize - index) * sizeof(T));
424  }
425 
426  // Deletes element at index and moves the last element into its place
427  void QuickDelete(UINT index)
428  {
429  D3DXASSERT(index < m_CurSize);
430 
431  -- m_CurSize;
432  memcpy((T*)m_pData + index, (T*)m_pData + m_CurSize, sizeof(T));
433  }
434 
435  inline UINT GetSize() const
436  {
437  return m_CurSize;
438  }
439 
440  inline T* GetData() const
441  {
442  return (T*)m_pData;
443  }
444 
445  UINT FindIndexOf(void *pEntry) const
446  {
447  UINT i;
448 
449  for (i = 0; i < m_CurSize; ++ i)
450  {
451  if (((T*)m_pData + i) == pEntry)
452  return i;
453  }
454 
455  return -1;
456  }
457 
458  void Sort(int (__cdecl *pfnCompare)(const void *pElem1, const void *pElem2))
459  {
460  qsort(m_pData, m_CurSize, sizeof(T), pfnCompare);
461  }
462 };
463 
465 // CEffectVectorOwner - implements a vector of ptrs to objects. The vector owns the objects.
467 template<class T> class CEffectVectorOwner : public CEffectVector<T*>
468 {
469 public:
471  {
472  Clear();
473  UINT i;
474 
475  for (i=0; i<m_CurSize; i++)
476  SAFE_DELETE(((T**)m_pData)[i]);
477 
478  SAFE_DELETE_ARRAY(m_pData);
479  }
480 
481  void Clear()
482  {
483  Empty();
484  SAFE_DELETE_ARRAY(m_pData);
485  m_MaxSize = 0;
486  }
487 
488  void Empty()
489  {
490  UINT i;
491 
492  // manually invoke destructor on all elements
493  for (i = 0; i < m_CurSize; ++ i)
494  {
495  SAFE_DELETE(((T**)m_pData)[i]);
496  }
497  m_CurSize = 0;
498  m_hLastError = S_OK;
499  }
500 
501  void Delete(UINT index)
502  {
503  D3DXASSERT(index < m_CurSize);
504 
505  SAFE_DELETE(((T**)m_pData)[index]);
506 
508  }
509 };
510 
511 
513 // Checked UINT, DWORD64
514 // Use CheckedNumber only with UINT and DWORD64
516 template <class T, T MaxValue> class CheckedNumber
517 {
518  T m_Value;
519  BOOL m_bValid;
520 
521 public:
523  {
524  m_Value = 0;
525  m_bValid = TRUE;
526  }
527 
529  {
530  m_Value = value;
531  m_bValid = TRUE;
532  }
533 
535  {
536  m_bValid = value.m_bValid;
537  m_Value = value.m_Value;
538  }
539 
541  {
542  CheckedNumber<T, MaxValue> Res(*this);
543  return Res+=other;
544  }
545 
547  {
548  if (!other.m_bValid)
549  {
550  m_bValid = FALSE;
551  }
552  else
553  {
554  m_Value += other.m_Value;
555 
556  if (m_Value < other.m_Value)
557  m_bValid = FALSE;
558  }
559 
560  return *this;
561  }
562 
564  {
565  CheckedNumber<T, MaxValue> Res(*this);
566  return Res*=other;
567  }
568 
570  {
571  if (!other.m_bValid)
572  {
573  m_bValid = FALSE;
574  }
575  else
576  {
577  if (other.m_Value != 0)
578  {
579  if (m_Value > MaxValue / other.m_Value)
580  {
581  m_bValid = FALSE;
582  }
583  }
584  m_Value *= other.m_Value;
585  }
586 
587  return *this;
588  }
589 
590  HRESULT GetValue(T *pValue)
591  {
592  if (!m_bValid)
593  {
594  *pValue = -1;
595  return E_FAIL;
596  }
597 
598  *pValue = m_Value;
599  return S_OK;
600  }
601 };
602 
605 
606 
608 // Data Block Store - A linked list of allocations
610 
612 {
613 protected:
614  UINT m_size;
615  UINT m_maxSize;
616  BYTE *m_pData;
618 
619  BOOL m_IsAligned; // Whether or not to align the data to c_DataAlignment
620 
621 public:
622  // AddData appends an existing use buffer to the data block
623  HRESULT AddData(const void *pNewData, UINT bufferSize, CDataBlock **ppBlock);
624 
625  // Allocate reserves bufferSize bytes of contiguous memory and returns a pointer to the user
626  void* Allocate(UINT bufferSize, CDataBlock **ppBlock);
627 
628  void EnableAlignment();
629 
630  CDataBlock();
631  ~CDataBlock();
632 
633  friend class CDataBlockStore;
634 };
635 
636 
638 {
639 protected:
642  UINT m_Size;
643  UINT m_Offset; // m_Offset gets added to offsets returned from AddData & AddString. Use this to set a global for the entire string block
644  BOOL m_IsAligned; // Whether or not to align the data to c_DataAlignment
645 
646 public:
647 #if _DEBUG
648  UINT m_cAllocations;
649 #endif
650 
651 public:
652  HRESULT AddString(LPCSTR pString, UINT *pOffset); // Writes a null-terminated string to buffer
653  HRESULT AddData(const void *pNewData, UINT bufferSize, UINT *pOffset); // Writes data block to buffer
654 
655  void* Allocate(UINT buffferSize); // Memory allocator support
656  UINT GetSize();
657  void EnableAlignment();
658 
659  CDataBlockStore();
660  ~CDataBlockStore();
661 };
662 
663 // Custom allocator that uses CDataBlockStore
664 // The trick is that we never free, so we don't have to keep as much state around
665 // Use PRIVATENEW in CEffectLoader
666 
667 static void* __cdecl operator new(size_t s, CDataBlockStore &pAllocator)
668 {
669  D3DXASSERT( s <= 0xffffffff );
670  return pAllocator.Allocate( (UINT)s );
671 }
672 
673 static void __cdecl operator delete(void* p, CDataBlockStore &pAllocator)
674 {
675 }
676 
677 
679 // Hash table
681 
682 #define HASH_MIX(a,b,c) \
683 { \
684  a -= b; a -= c; a ^= (c>>13); \
685  b -= c; b -= a; b ^= (a<<8); \
686  c -= a; c -= b; c ^= (b>>13); \
687  a -= b; a -= c; a ^= (c>>12); \
688  b -= c; b -= a; b ^= (a<<16); \
689  c -= a; c -= b; c ^= (b>>5); \
690  a -= b; a -= c; a ^= (c>>3); \
691  b -= c; b -= a; b ^= (a<<10); \
692  c -= a; c -= b; c ^= (b>>15); \
693 }
694 
695 static UINT ComputeHash(BYTE *pb, UINT cbToHash)
696 {
697  UINT a;
698  UINT b;
699  UINT c;
700  UINT cbLeft;
701 
702  cbLeft = cbToHash;
703 
704  a = b = 0x9e3779b9; // the golden ratio; an arbitrary value
705  c = 0;
706 
707  while (cbLeft >= 12)
708  {
709  UINT *pdw = reinterpret_cast<UINT *>(pb);
710 
711  a += pdw[0];
712  b += pdw[1];
713  c += pdw[2];
714 
715  HASH_MIX(a,b,c);
716  pb += 12;
717  cbLeft -= 12;
718  }
719 
720  c += cbToHash;
721 
722  switch(cbLeft) // all the case statements fall through
723  {
724  case 11: c+=((UINT) pb[10] << 24);
725  case 10: c+=((UINT) pb[9] << 16);
726  case 9 : c+=((UINT) pb[8] << 8);
727  // the first byte of c is reserved for the length
728  case 8 : b+=((UINT) pb[7] << 24);
729  case 7 : b+=((UINT) pb[6] << 16);
730  case 6 : b+=((UINT) pb[5] << 8);
731  case 5 : b+=pb[4];
732  case 4 : a+=((UINT) pb[3] << 24);
733  case 3 : a+=((UINT) pb[2] << 16);
734  case 2 : a+=((UINT) pb[1] << 8);
735  case 1 : a+=pb[0];
736  }
737 
738  HASH_MIX(a,b,c);
739 
740  return c;
741 }
742 
743 static UINT ComputeHashLower(BYTE *pb, UINT cbToHash)
744 {
745  UINT a;
746  UINT b;
747  UINT c;
748  UINT cbLeft;
749 
750  cbLeft = cbToHash;
751 
752  a = b = 0x9e3779b9; // the golden ratio; an arbitrary value
753  c = 0;
754 
755  while (cbLeft >= 12)
756  {
757  BYTE pbT[12];
758  for( UINT i = 0; i < 12; i++ )
759  pbT[i] = (BYTE)tolower(pb[i]);
760 
761  UINT *pdw = reinterpret_cast<UINT *>(pbT);
762 
763  a += pdw[0];
764  b += pdw[1];
765  c += pdw[2];
766 
767  HASH_MIX(a,b,c);
768  pb += 12;
769  cbLeft -= 12;
770  }
771 
772  c += cbToHash;
773 
774  BYTE pbT[12];
775  for( UINT i = 0; i < cbLeft; i++ )
776  pbT[i] = (BYTE)tolower(pb[i]);
777 
778  switch(cbLeft) // all the case statements fall through
779  {
780  case 11: c+=((UINT) pbT[10] << 24);
781  case 10: c+=((UINT) pbT[9] << 16);
782  case 9 : c+=((UINT) pbT[8] << 8);
783  // the first byte of c is reserved for the length
784  case 8 : b+=((UINT) pbT[7] << 24);
785  case 7 : b+=((UINT) pbT[6] << 16);
786  case 6 : b+=((UINT) pbT[5] << 8);
787  case 5 : b+=pbT[4];
788  case 4 : a+=((UINT) pbT[3] << 24);
789  case 3 : a+=((UINT) pbT[2] << 16);
790  case 2 : a+=((UINT) pbT[1] << 8);
791  case 1 : a+=pbT[0];
792  }
793 
794  HASH_MIX(a,b,c);
795 
796  return c;
797 }
798 
799 
800 static UINT ComputeHash(LPCSTR pString)
801 {
802  return ComputeHash((BYTE*) pString, (UINT)strlen(pString));
803 }
804 
805 
806 // 1) these numbers are prime
807 // 2) each is slightly less than double the last
808 // 4) each is roughly in between two powers of 2;
809 // (2^n hash table sizes are VERY BAD; they effectively truncate your
810 // precision down to the n least significant bits of the hash)
811 static const UINT c_PrimeSizes[] =
812 {
813  11,
814  23,
815  53,
816  97,
817  193,
818  389,
819  769,
820  1543,
821  3079,
822  6151,
823  12289,
824  24593,
825  49157,
826  98317,
827  196613,
828  393241,
829  786433,
830  1572869,
831  3145739,
832  6291469,
833  12582917,
834  25165843,
835  50331653,
836  100663319,
837  201326611,
838  402653189,
839  805306457,
840  1610612741,
841 };
842 
843 static const UINT c_NumPrimes = sizeof(c_PrimeSizes) / sizeof(UINT);
844 
845 template<typename T, BOOL (*pfnIsEqual)(const T &Data1, const T &Data2)>
847 {
848 protected:
849 
850  struct SHashEntry
851  {
852  UINT Hash;
853  T Data;
855  };
856 
857  // Array of hash entries
862 
863 public:
864  class CIterator
865  {
866  friend class CEffectHashTable;
867 
868  protected:
871 
872  public:
874  {
875  D3DXASSERT(NULL != pHashEntry);
876  return pHashEntry->Data;
877  }
878 
879  UINT GetHash()
880  {
881  D3DXASSERT(NULL != pHashEntry);
882  return pHashEntry->Hash;
883  }
884  };
885 
887  {
888  m_rgpHashEntries = NULL;
889  m_NumHashSlots = 0;
890  m_NumEntries = 0;
891  m_bOwnHashEntryArray = false;
892  }
893 
894  HRESULT Initialize(CEffectHashTable *pOther)
895  {
896  HRESULT hr = S_OK;
897  SHashEntry **rgpNewHashEntries = NULL;
898  SHashEntry ***rgppListEnds = NULL;
899  UINT i;
900  UINT valuesMigrated = 0;
901  UINT actualSize;
902 
903  Cleanup();
904 
905  actualSize = pOther->m_NumHashSlots;
906  VN( rgpNewHashEntries = NEW SHashEntry*[actualSize] );
907 
908  ZeroMemory(rgpNewHashEntries, sizeof(SHashEntry*) * actualSize);
909 
910  // Expensive operation: rebuild the hash table
911  CIterator iter, nextIter;
912  pOther->GetFirstEntry(&iter);
913  while (!pOther->PastEnd(&iter))
914  {
915  UINT index = iter.GetHash() % actualSize;
916 
917  // we need to advance to the next element
918  // before we seize control of this element and move
919  // it to the new table
920  nextIter = iter;
921  pOther->GetNextEntry(&nextIter);
922 
923  // seize this hash entry, migrate it to the new table
924  SHashEntry *pNewEntry;
925  VN( pNewEntry = NEW SHashEntry );
926 
927  pNewEntry->pNext = rgpNewHashEntries[index];
928  pNewEntry->Data = iter.pHashEntry->Data;
929  pNewEntry->Hash = iter.pHashEntry->Hash;
930  rgpNewHashEntries[index] = pNewEntry;
931 
932  iter = nextIter;
933  ++ valuesMigrated;
934  }
935 
936  D3DXASSERT(valuesMigrated == pOther->m_NumEntries);
937 
938  m_rgpHashEntries = rgpNewHashEntries;
939  m_NumHashSlots = actualSize;
940  m_NumEntries = pOther->m_NumEntries;
941  m_bOwnHashEntryArray = true;
942  rgpNewHashEntries = NULL;
943 
944 lExit:
945  SAFE_DELETE_ARRAY( rgpNewHashEntries );
946  return hr;
947  }
948 
949 protected:
950  void CleanArray()
951  {
952  if (m_bOwnHashEntryArray)
953  {
954  SAFE_DELETE_ARRAY(m_rgpHashEntries);
955  m_bOwnHashEntryArray = false;
956  }
957  }
958 
959 public:
960  void Cleanup()
961  {
962  UINT i;
963  for (i = 0; i < m_NumHashSlots; ++ i)
964  {
965  SHashEntry *pCurrentEntry = m_rgpHashEntries[i];
966  SHashEntry *pTempEntry;
967  while (NULL != pCurrentEntry)
968  {
969  pTempEntry = pCurrentEntry->pNext;
970  SAFE_DELETE(pCurrentEntry);
971  pCurrentEntry = pTempEntry;
972  -- m_NumEntries;
973  }
974  }
975  CleanArray();
976  m_NumHashSlots = 0;
977  D3DXASSERT(m_NumEntries == 0);
978  }
979 
981  {
982  Cleanup();
983  }
984 
985  static UINT GetNextHashTableSize(__in UINT DesiredSize)
986  {
987  // figure out the next logical size to use
988  for (UINT i = 0; i < c_NumPrimes; ++ i)
989  {
990  if (c_PrimeSizes[i] >= DesiredSize)
991  {
992  return c_PrimeSizes[i];
993  }
994  }
995 
996  return DesiredSize;
997  }
998 
999  // O(n) function
1000  // Grows to the next suitable size (based off of the prime number table)
1001  // DesiredSize is merely a suggestion
1002  HRESULT Grow(__in UINT DesiredSize,
1003  __in UINT ProvidedArraySize = 0,
1004  __in_ecount_opt(ProvidedArraySize)
1005  void** ProvidedArray = NULL,
1006  __in bool OwnProvidedArray = false)
1007  {
1008  HRESULT hr = S_OK;
1009  SHashEntry **rgpNewHashEntries = NULL;
1010  SHashEntry ***rgppListEnds = NULL;
1011  UINT valuesMigrated = 0;
1012  UINT actualSize;
1013 
1014  VB( DesiredSize > m_NumHashSlots );
1015 
1016  actualSize = GetNextHashTableSize(DesiredSize);
1017 
1018  if (ProvidedArray &&
1019  ProvidedArraySize >= actualSize)
1020  {
1021  rgpNewHashEntries = reinterpret_cast<SHashEntry**>(ProvidedArray);
1022  }
1023  else
1024  {
1025  OwnProvidedArray = true;
1026 
1027  VN( rgpNewHashEntries = NEW SHashEntry*[actualSize] );
1028  }
1029 
1030  ZeroMemory(rgpNewHashEntries, sizeof(SHashEntry*) * actualSize);
1031 
1032  // Expensive operation: rebuild the hash table
1033  CIterator iter, nextIter;
1034  GetFirstEntry(&iter);
1035  while (!PastEnd(&iter))
1036  {
1037  UINT index = iter.GetHash() % actualSize;
1038 
1039  // we need to advance to the next element
1040  // before we seize control of this element and move
1041  // it to the new table
1042  nextIter = iter;
1043  GetNextEntry(&nextIter);
1044 
1045  // seize this hash entry, migrate it to the new table
1046  iter.pHashEntry->pNext = rgpNewHashEntries[index];
1047  rgpNewHashEntries[index] = iter.pHashEntry;
1048 
1049  iter = nextIter;
1050  ++ valuesMigrated;
1051  }
1052 
1053  D3DXASSERT(valuesMigrated == m_NumEntries);
1054 
1055  CleanArray();
1056  m_rgpHashEntries = rgpNewHashEntries;
1057  m_NumHashSlots = actualSize;
1058  m_bOwnHashEntryArray = OwnProvidedArray;
1059 
1060 lExit:
1061  return hr;
1062  }
1063 
1064  HRESULT AutoGrow()
1065  {
1066  // arbitrary heuristic -- grow if 1:1
1067  if (m_NumEntries >= m_NumHashSlots)
1068  {
1069  // grows this hash table so that it is roughly 50% full
1070  return Grow(m_NumEntries * 2 + 1);
1071  }
1072  return S_OK;
1073  }
1074 
1075 #if _DEBUG
1076  void PrintHashTableStats()
1077  {
1078  if (m_NumHashSlots == 0)
1079  {
1080  DPF(0, "Uninitialized hash table!");
1081  return;
1082  }
1083 
1084  UINT i;
1085  float variance = 0.0f;
1086  float mean = (float)m_NumEntries / (float)m_NumHashSlots;
1087  UINT unusedSlots = 0;
1088 
1089  DPF(0, "Hash table slots: %d, Entries in table: %d", m_NumHashSlots, m_NumEntries);
1090 
1091  for (i = 0; i < m_NumHashSlots; ++ i)
1092  {
1093  UINT entries = 0;
1094  SHashEntry *pCurrentEntry = m_rgpHashEntries[i];
1095 
1096  while (NULL != pCurrentEntry)
1097  {
1098  SHashEntry *pCurrentEntry2 = m_rgpHashEntries[i];
1099 
1100  // check other hash entries in this slot for hash collisions or duplications
1101  while (pCurrentEntry2 != pCurrentEntry)
1102  {
1103  if (pCurrentEntry->Hash == pCurrentEntry2->Hash)
1104  {
1105  if (pfnIsEqual(pCurrentEntry->Data, pCurrentEntry2->Data))
1106  {
1107  D3DXASSERT(0);
1108  DPF(0, "Duplicate entry (identical hash, identical data) found!");
1109  }
1110  else
1111  {
1112  DPF(0, "Hash collision (hash: %d)", pCurrentEntry->Hash);
1113  }
1114  }
1115  pCurrentEntry2 = pCurrentEntry2->pNext;
1116  }
1117 
1118  pCurrentEntry = pCurrentEntry->pNext;
1119  ++ entries;
1120  }
1121 
1122  if (0 == entries)
1123  {
1124  ++ unusedSlots;
1125  }
1126 
1127  // mean must be greater than 0 at this point
1128  variance += (float)entries * (float)entries / mean;
1129  }
1130 
1131  variance /= max(1.0f, (m_NumHashSlots - 1));
1132  variance -= (mean * mean);
1133 
1134  DPF(0, "Mean number of entries per slot: %f, Standard deviation: %f, Unused slots; %d", mean, variance, unusedSlots);
1135  }
1136 #endif // _DEBUG
1137 
1138  // S_OK if element is found, E_FAIL otherwise
1139  HRESULT FindValueWithHash(T Data, UINT Hash, CIterator *pIterator)
1140  {
1141  D3DXASSERT(m_NumHashSlots > 0);
1142 
1143  UINT index = Hash % m_NumHashSlots;
1144  SHashEntry *pEntry = m_rgpHashEntries[index];
1145  while (NULL != pEntry)
1146  {
1147  if (Hash == pEntry->Hash && pfnIsEqual(pEntry->Data, Data))
1148  {
1149  pIterator->ppHashSlot = m_rgpHashEntries + index;
1150  pIterator->pHashEntry = pEntry;
1151  return S_OK;
1152  }
1153  pEntry = pEntry->pNext;
1154  }
1155  return E_FAIL;
1156  }
1157 
1158  // S_OK if element is found, E_FAIL otherwise
1159  HRESULT FindFirstMatchingValue(UINT Hash, CIterator *pIterator)
1160  {
1161  D3DXASSERT(m_NumHashSlots > 0);
1162 
1163  UINT index = Hash % m_NumHashSlots;
1164  SHashEntry *pEntry = m_rgpHashEntries[index];
1165  while (NULL != pEntry)
1166  {
1167  if (Hash == pEntry->Hash)
1168  {
1169  pIterator->ppHashSlot = m_rgpHashEntries + index;
1170  pIterator->pHashEntry = pEntry;
1171  return S_OK;
1172  }
1173  pEntry = pEntry->pNext;
1174  }
1175  return E_FAIL;
1176  }
1177 
1178  // Adds data at the specified hash slot without checking for existence
1179  HRESULT AddValueWithHash(T Data, UINT Hash)
1180  {
1181  HRESULT hr = S_OK;
1182 
1183  D3DXASSERT(m_NumHashSlots > 0);
1184 
1185  SHashEntry *pHashEntry;
1186  UINT index = Hash % m_NumHashSlots;
1187 
1188  VN( pHashEntry = NEW SHashEntry );
1189  pHashEntry->pNext = m_rgpHashEntries[index];
1190  pHashEntry->Data = Data;
1191  pHashEntry->Hash = Hash;
1192  m_rgpHashEntries[index] = pHashEntry;
1193 
1194  ++ m_NumEntries;
1195 
1196 lExit:
1197  return hr;
1198  }
1199 
1200  // Iterator code:
1201  //
1202  // CMyHashTable::CIterator myIt;
1203  // for (myTable.GetFirstEntry(&myIt); !myTable.PastEnd(&myIt); myTable.GetNextEntry(&myIt)
1204  // { myTable.GetData(&myIt); }
1205  void GetFirstEntry(CIterator *pIterator)
1206  {
1207  SHashEntry **ppEnd = m_rgpHashEntries + m_NumHashSlots;
1208  pIterator->ppHashSlot = m_rgpHashEntries;
1209  while (pIterator->ppHashSlot < ppEnd)
1210  {
1211  if (NULL != *(pIterator->ppHashSlot))
1212  {
1213  pIterator->pHashEntry = *(pIterator->ppHashSlot);
1214  return;
1215  }
1216  ++ pIterator->ppHashSlot;
1217  }
1218  }
1219 
1220  BOOL PastEnd(CIterator *pIterator)
1221  {
1222  SHashEntry **ppEnd = m_rgpHashEntries + m_NumHashSlots;
1223  D3DXASSERT(pIterator->ppHashSlot >= m_rgpHashEntries && pIterator->ppHashSlot <= ppEnd);
1224  return (pIterator->ppHashSlot == ppEnd);
1225  }
1226 
1227  void GetNextEntry(CIterator *pIterator)
1228  {
1229  SHashEntry **ppEnd = m_rgpHashEntries + m_NumHashSlots;
1230  D3DXASSERT(pIterator->ppHashSlot >= m_rgpHashEntries && pIterator->ppHashSlot <= ppEnd);
1231  D3DXASSERT(NULL != pIterator->pHashEntry);
1232 
1233  pIterator->pHashEntry = pIterator->pHashEntry->pNext;
1234  if (NULL != pIterator->pHashEntry)
1235  {
1236  return;
1237  }
1238 
1239  ++ pIterator->ppHashSlot;
1240  while (pIterator->ppHashSlot < ppEnd)
1241  {
1242  pIterator->pHashEntry = *(pIterator->ppHashSlot);
1243  if (NULL != pIterator->pHashEntry)
1244  {
1245  return;
1246  }
1247  ++ pIterator->ppHashSlot;
1248  }
1249  // hit the end of the list, ppHashSlot == ppEnd
1250  }
1251 
1252  void RemoveEntry(CIterator *pIterator)
1253  {
1254  SHashEntry *pTemp;
1255  SHashEntry **ppPrev;
1256  SHashEntry **ppEnd = m_rgpHashEntries + m_NumHashSlots;
1257 
1258  D3DXASSERT(pIterator && !PastEnd(pIterator));
1259  ppPrev = pIterator->ppHashSlot;
1260  pTemp = *ppPrev;
1261  while (pTemp)
1262  {
1263  if (pTemp == pIterator->pHashEntry)
1264  {
1265  *ppPrev = pTemp->pNext;
1266  pIterator->ppHashSlot = ppEnd;
1267  delete pTemp;
1268  return;
1269  }
1270  ppPrev = &pTemp->pNext;
1271  pTemp = pTemp->pNext;
1272  }
1273 
1274  // Should never get here
1275  D3DXASSERT(0);
1276  }
1277 
1278 };
1279 
1280 // Allocates the hash slots on the regular heap (since the
1281 // hash table can grow), but all hash entries are allocated on
1282 // a private heap
1283 
1284 template<typename T, BOOL (*pfnIsEqual)(const T &Data1, const T &Data2)>
1286 {
1287 protected:
1289 
1290 public:
1292  {
1293  m_pPrivateHeap = NULL;
1294  }
1295 
1296  void Cleanup()
1297  {
1298  CleanArray();
1299  m_NumHashSlots = 0;
1300  m_NumEntries = 0;
1301  }
1302 
1304  {
1305  Cleanup();
1306  }
1307 
1308  // Call this only once
1309  void SetPrivateHeap(CDataBlockStore *pPrivateHeap)
1310  {
1311  D3DXASSERT(NULL == m_pPrivateHeap);
1312  m_pPrivateHeap = pPrivateHeap;
1313  }
1314 
1315  // Adds data at the specified hash slot without checking for existence
1316  HRESULT AddValueWithHash(T Data, UINT Hash)
1317  {
1318  HRESULT hr = S_OK;
1319 
1320  D3DXASSERT(NULL != m_pPrivateHeap);
1321  D3DXASSERT(m_NumHashSlots > 0);
1322 
1323  SHashEntry *pHashEntry;
1324  UINT index = Hash % m_NumHashSlots;
1325 
1326  VN( pHashEntry = new(*m_pPrivateHeap) SHashEntry );
1327  pHashEntry->pNext = m_rgpHashEntries[index];
1328  pHashEntry->Data = Data;
1329  pHashEntry->Hash = Hash;
1330  m_rgpHashEntries[index] = pHashEntry;
1331 
1332  ++ m_NumEntries;
1333 
1334 lExit:
1335  return hr;
1336  }
1337 };
static UINT GetNextHashTableSize(__in UINT DesiredSize)
Definition: d3dxGlobal.h:985
BOOL m_IsAligned
Definition: d3dxGlobal.h:619
UINT m_size
Definition: d3dxGlobal.h:614
SHashEntry * pNext
Definition: d3dxGlobal.h:854
T * AddRange(UINT count)
Definition: d3dxGlobal.h:328
CheckedNumber< T, MaxValue > & operator+=(const CheckedNumber< T, MaxValue > &other)
Definition: d3dxGlobal.h:546
void SetPrivateHeap(CDataBlockStore *pPrivateHeap)
Definition: d3dxGlobal.h:1309
HRESULT FindFirstMatchingValue(UINT Hash, CIterator *pIterator)
Definition: d3dxGlobal.h:1159
BYTE * m_pData
Definition: d3dxGlobal.h:183
SHashEntry ** m_rgpHashEntries
Definition: d3dxGlobal.h:858
HRESULT Reserve(UINT DesiredSize)
Definition: d3dxGlobal.h:192
void GetNextEntry(CIterator *pIterator)
Definition: d3dxGlobal.h:1227
CDataBlock * m_pFirst
Definition: d3dxGlobal.h:640
void Clear()
Definition: d3dxGlobal.h:284
T * GetData() const
Definition: d3dxGlobal.h:440
void Delete(UINT index)
Definition: d3dxGlobal.h:501
HRESULT Add(const T &var)
Definition: d3dxGlobal.h:349
#define DPF()
Definition: d3dx11dbg.h:47
#define SAFE_DELETE_ARRAY(p)
Definition: d3dxGlobal.h:25
UINT Hash
Definition: d3dxGlobal.h:852
HRESULT FindValueWithHash(T Data, UINT Hash, CIterator *pIterator)
Definition: d3dxGlobal.h:1139
void ClearWithoutDestructor()
Definition: d3dxGlobal.h:294
HRESULT m_hLastError
Definition: d3dxGlobal.h:231
HRESULT GetValue(T *pValue)
Definition: d3dxGlobal.h:590
CheckedNumber< DWORD64, _UI64_MAX > CCheckedDword64
Definition: d3dxGlobal.h:604
void Empty()
Definition: d3dxGlobal.h:306
void SwapVector(CEffectVector< T > &vOther)
Definition: d3dxGlobal.h:250
D3DX11INLINE UINT AlignToPowerOf2(UINT Value, UINT Alignment)
Definition: d3dxGlobal.h:57
bool m_bOwnHashEntryArray
Definition: d3dxGlobal.h:861
UINT FindIndexOf(void *pEntry) const
Definition: d3dxGlobal.h:445
HRESULT AddValueWithHash(T Data, UINT Hash)
Definition: d3dxGlobal.h:1179
void QuickDelete(UINT index)
Definition: d3dxGlobal.h:427
void GetFirstEntry(CIterator *pIterator)
Definition: d3dxGlobal.h:1205
UINT m_maxSize
Definition: d3dxGlobal.h:615
Definition: d3dxGlobal.h:850
HRESULT Grow(__in UINT DesiredSize, __in UINT ProvidedArraySize=0, __in_ecount_opt(ProvidedArraySize) void **ProvidedArray=NULL, __in bool OwnProvidedArray=false)
Definition: d3dxGlobal.h:1002
#define VB(x)
Definition: d3dxGlobal.h:41
#define VN(x)
Definition: d3dxGlobal.h:40
T & operator[](UINT index)
Definition: d3dxGlobal.h:411
#define HASH_MIX(a, b, c)
Definition: d3dxGlobal.h:682
CheckedNumber< T, MaxValue > & operator*=(const CheckedNumber< T, MaxValue > &other)
Definition: d3dxGlobal.h:569
void Sort(int(__cdecl *pfnCompare)(const void *pElem1, const void *pElem2))
Definition: d3dxGlobal.h:458
void RemoveEntry(CIterator *pIterator)
Definition: d3dxGlobal.h:1252
#define ANALYSIS_ASSUME(x)
Definition: d3dxGlobal.h:50
CheckedNumber< UINT, _UI32_MAX > CCheckedDword
Definition: d3dxGlobal.h:603
BYTE * m_pData
Definition: d3dxGlobal.h:616
CheckedNumber< T, MaxValue > & operator*(const CheckedNumber< T, MaxValue > &other)
Definition: d3dxGlobal.h:563
ID3D11Buffer D3D11_BUFFER_DESC void * pData
Definition: raSDKmesh.h:238
HRESULT AutoGrow()
Definition: d3dxGlobal.h:1064
CDataBlock * m_pNext
Definition: d3dxGlobal.h:617
UINT GetSize() const
Definition: d3dxGlobal.h:435
#define D3DXASSERT(condition)
Definition: d3dx11dbg.h:60
CDataBlockStore * m_pPrivateHeap
Definition: d3dxGlobal.h:1288
D3DX11INLINE void dwordMemcpy(__out_bcount(uByteCount) void *__restrict pDest, __in_bcount(uByteCount) CONST void *__restrict pSource, UINT uByteCount)
Definition: d3dxGlobal.h:74
BOOL PastEnd(CIterator *pIterator)
Definition: d3dxGlobal.h:1220
HRESULT CopyFrom(CEffectVector< T > &vOther)
Definition: d3dxGlobal.h:259
#define NEW
Definition: d3dx11dbg.h:27
void Delete(UINT index)
Definition: d3dxGlobal.h:418
CDataBlock * m_pLast
Definition: d3dxGlobal.h:641
HRESULT Initialize(CEffectHashTable *pOther)
Definition: d3dxGlobal.h:894
#define SAFE_DELETE(p)
Definition: d3dxGlobal.h:26
HRESULT InsertRange(const T *pVar, UINT index, UINT count)
Definition: d3dxGlobal.h:391
HRESULT AddValueWithHash(T Data, UINT Hash)
Definition: d3dxGlobal.h:1316
HRESULT Insert(const T &var, UINT index)
Definition: d3dxGlobal.h:377
CheckedNumber< T, MaxValue > & operator+(const CheckedNumber< T, MaxValue > &other)
Definition: d3dxGlobal.h:540
HRESULT AddRange(const T *pVar, UINT count)
Definition: d3dxGlobal.h:360
T Data
Definition: d3dxGlobal.h:853
HRESULT Grow()
Definition: d3dxGlobal.h:187