Fix reading Time zone rules using Julian days (#17672)
[platform/upstream/coreclr.git] / src / jit / jithashtable.h
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4
5 #pragma once
6
7 // JitHashTable implements a mapping from a Key type to a Value type,
8 // via a hash table.
9
10 // JitHashTable takes four template parameters:
11 //    Key, KeyFuncs, Value, Allocator and Behavior.
12 // We don't assume that Key has hash or equality functions specific names;
13 // rather, we assume that KeyFuncs has the following static methods
14 //    int GetHashCode(Key)
15 //    bool Equals(Key, Key)
16 // and use those. An instantiator can thus make a small "adaptor class"
17 // to invoke existing instance method hash and/or equality functions.
18 // If the implementor of a candidate Key class K understands this convention,
19 // these static methods can be implemented by K, so that K can be used
20 // as the actual arguments for the both Key and KeyFuncs template parameters.
21 //
22 // The "Behavior" parameter must provide the following static members:
23 //
24 // s_growth_factor_numerator
25 // s_growth_factor_denominator                  Factor to grow allocation (numerator/denominator).
26 //                                              Typically inherited from default traits (3/2)
27 //
28 // s_density_factor_numerator
29 // s_density_factor_denominator                 Maxium occupied density of table before growth
30 //                                              occurs (num/denom).  Typically inherited (3/4).
31 //
32 // s_minimum_allocation                         Minimum table allocation count (size on first growth.)  It is
33 //                                              probably preferable to call Reallocate on initialization rather
34 //                                              than override this from the default traits.
35 //
36 // NoMemory()                                   Called when the hash table is unable to grow due to potential
37 //                                              overflow or the lack of a sufficiently large prime.
38
39 class JitHashTableBehavior
40 {
41 public:
42     static const unsigned s_growth_factor_numerator   = 3;
43     static const unsigned s_growth_factor_denominator = 2;
44
45     static const unsigned s_density_factor_numerator   = 3;
46     static const unsigned s_density_factor_denominator = 4;
47
48     static const unsigned s_minimum_allocation = 7;
49
50     inline static void DECLSPEC_NORETURN NoMemory()
51     {
52         NOMEM();
53     }
54 };
55
56 // Stores info about primes, including the magic number and shift amount needed
57 // to implement a divide without using the divide instruction
58 class JitPrimeInfo
59 {
60 public:
61     JitPrimeInfo() : prime(0), magic(0), shift(0)
62     {
63     }
64     JitPrimeInfo(unsigned p, unsigned m, unsigned s) : prime(p), magic(m), shift(s)
65     {
66     }
67     unsigned prime;
68     unsigned magic;
69     unsigned shift;
70
71     // Compute `numerator` / `prime` using magic division
72     unsigned magicNumberDivide(unsigned numerator) const
73     {
74         unsigned __int64 num     = numerator;
75         unsigned __int64 mag     = magic;
76         unsigned __int64 product = (num * mag) >> (32 + shift);
77         return (unsigned)product;
78     }
79
80     // Compute `numerator` % `prime` using magic division
81     unsigned magicNumberRem(unsigned numerator) const
82     {
83         unsigned div    = magicNumberDivide(numerator);
84         unsigned result = numerator - (div * prime);
85         assert(result == numerator % prime);
86         return result;
87     }
88 };
89
90 // Table of primes and their magic-number-divide constant.
91 // For more info see the book "Hacker's Delight" chapter 10.9 "Unsigned Division by Divisors >= 1"
92 // These were selected by looking for primes, each roughly twice as big as the next, having
93 // 32-bit magic numbers, (because the algorithm for using 33-bit magic numbers is slightly slower).
94
95 // clang-format off
96 SELECTANY const JitPrimeInfo jitPrimeInfo[]
97 {
98     JitPrimeInfo(9,         0x38e38e39, 1),
99     JitPrimeInfo(23,        0xb21642c9, 4),
100     JitPrimeInfo(59,        0x22b63cbf, 3),
101     JitPrimeInfo(131,       0xfa232cf3, 7),
102     JitPrimeInfo(239,       0x891ac73b, 7),
103     JitPrimeInfo(433,       0x975a751,  4),
104     JitPrimeInfo(761,       0x561e46a5, 8),
105     JitPrimeInfo(1399,      0xbb612aa3, 10),
106     JitPrimeInfo(2473,      0x6a009f01, 10),
107     JitPrimeInfo(4327,      0xf2555049, 12),
108     JitPrimeInfo(7499,      0x45ea155f, 11),
109     JitPrimeInfo(12973,     0x1434f6d3, 10),               
110     JitPrimeInfo(22433,     0x2ebe18db, 12),               
111     JitPrimeInfo(46559,     0xb42bebd5, 15),               
112     JitPrimeInfo(96581,     0xadb61b1b, 16),
113     JitPrimeInfo(200341,    0x29df2461, 15),
114     JitPrimeInfo(415517,    0xa181c46d, 18),
115     JitPrimeInfo(861719,    0x4de0bde5, 18),
116     JitPrimeInfo(1787021,   0x9636c46f, 20),
117     JitPrimeInfo(3705617,   0x4870adc1, 20),
118     JitPrimeInfo(7684087,   0x8bbc5b83, 22),
119     JitPrimeInfo(15933877,  0x86c65361, 23),           
120     JitPrimeInfo(33040633,  0x40fec79b, 23),           
121     JitPrimeInfo(68513161,  0x7d605cd1, 25),           
122     JitPrimeInfo(142069021, 0xf1da390b, 27),           
123     JitPrimeInfo(294594427, 0x74a2507d, 27),
124     JitPrimeInfo(733045421, 0x5dbec447, 28),
125 };
126 // clang-format on
127
128 // Hash table class definition
129
130 template <typename Key,
131           typename KeyFuncs,
132           typename Value,
133           typename Allocator = CompAllocator,
134           typename Behavior  = JitHashTableBehavior>
135 class JitHashTable
136 {
137 public:
138     class KeyIterator;
139
140     //------------------------------------------------------------------------
141     // JitHashTable: Construct an empty JitHashTable object.
142     //
143     // Arguments:
144     //    alloc - the allocator to be used by the new JitHashTable object
145     //
146     // Notes:
147     //    JitHashTable always starts out empty, with no allocation overhead.
148     //    Call Reallocate to prime with an initial size if desired.
149     //
150     JitHashTable(Allocator* alloc) : m_alloc(alloc), m_table(nullptr), m_tableSizeInfo(), m_tableCount(0), m_tableMax(0)
151     {
152         assert(m_alloc != nullptr);
153
154 #ifndef __GNUC__ // these crash GCC
155         static_assert_no_msg(Behavior::s_growth_factor_numerator > Behavior::s_growth_factor_denominator);
156         static_assert_no_msg(Behavior::s_density_factor_numerator < Behavior::s_density_factor_denominator);
157 #endif
158     }
159
160     //------------------------------------------------------------------------
161     // ~JitHashTable: Destruct the JitHashTable object.
162     //
163     // Notes:
164     //    Destructs all keys and values stored in the table and frees all
165     //    owned memory.
166     //
167     ~JitHashTable()
168     {
169         RemoveAll();
170     }
171
172     //------------------------------------------------------------------------
173     // Lookup: Get the value associated to the specified key, if any.
174     //
175     // Arguments:
176     //    k    - the key
177     //    pVal - pointer to a location used to store the associated value
178     //
179     // Return Value:
180     //    `true` if the key exists, `false` otherwise
181     //
182     // Notes:
183     //    If the key does not exist *pVal is not updated. pVal may be nullptr
184     //    so this function can be used to simply check if the key exists.
185     //
186     bool Lookup(Key k, Value* pVal = nullptr) const
187     {
188         Node* pN = FindNode(k);
189
190         if (pN != nullptr)
191         {
192             if (pVal != nullptr)
193             {
194                 *pVal = pN->m_val;
195             }
196             return true;
197         }
198         else
199         {
200             return false;
201         }
202     }
203
204     //------------------------------------------------------------------------
205     // Lookup: Get a pointer to the value associated to the specified key.
206     // if any.
207     //
208     // Arguments:
209     //    k - the key
210     //
211     // Return Value:
212     //    A pointer to the value associated with the specified key or nullptr
213     //    if the key is not found
214     //
215     // Notes:
216     //    This is similar to `Lookup` but avoids copying the value and allows
217     //    updating the value without using `Set`.
218     //
219     Value* LookupPointer(Key k) const
220     {
221         Node* pN = FindNode(k);
222
223         if (pN != nullptr)
224         {
225             return &(pN->m_val);
226         }
227         else
228         {
229             return nullptr;
230         }
231     }
232
233     //------------------------------------------------------------------------
234     // Set: Associate the specified value with the specified key.
235     //
236     // Arguments:
237     //    k - the key
238     //    v - the value
239     //
240     // Return Value:
241     //    `true` if the key already exists, `false` otherwise.
242     //
243     // Notes:
244     //    If the key already exists then its associated value is updated to
245     //    the new value.
246     //
247     bool Set(Key k, Value v)
248     {
249         CheckGrowth();
250
251         assert(m_tableSizeInfo.prime != 0);
252
253         unsigned index = GetIndexForKey(k);
254
255         Node* pN = m_table[index];
256         while ((pN != nullptr) && !KeyFuncs::Equals(k, pN->m_key))
257         {
258             pN = pN->m_next;
259         }
260         if (pN != nullptr)
261         {
262             pN->m_val = v;
263             return true;
264         }
265         else
266         {
267             Node* pNewNode = new (m_alloc) Node(m_table[index], k, v);
268             m_table[index] = pNewNode;
269             m_tableCount++;
270             return false;
271         }
272     }
273
274     //------------------------------------------------------------------------
275     // Emplace: Associates the specified key with a value constructed in-place
276     // using the supplied args if the key is not already present.
277     //
278     // Arguments:
279     //    k - the key
280     //    args - the args used to construct the value
281     //
282     // Return Value:
283     //    A pointer to the existing or newly constructed value.
284     //
285     template <class... Args>
286     Value* Emplace(Key k, Args&&... args)
287     {
288         CheckGrowth();
289
290         assert(m_tableSizeInfo.prime != 0);
291
292         unsigned index = GetIndexForKey(k);
293
294         Node* n = m_table[index];
295         while ((n != nullptr) && !KeyFuncs::Equals(k, n->m_key))
296         {
297             n = n->m_next;
298         }
299
300         if (n == nullptr)
301         {
302             n = new (m_alloc) Node(m_table[index], k, jitstd::forward<Args>(args)...);
303
304             m_table[index] = n;
305             m_tableCount++;
306         }
307
308         return &n->m_val;
309     }
310
311     //------------------------------------------------------------------------
312     // Remove: Remove the specified key and its associated value.
313     //
314     // Arguments:
315     //    k - the key
316     //
317     // Return Value:
318     //    `true` if the key exists, `false` otherwise.
319     //
320     // Notes:
321     //    Removing a inexistent key is not an error.
322     //
323     bool Remove(Key k)
324     {
325         unsigned index = GetIndexForKey(k);
326
327         Node*  pN  = m_table[index];
328         Node** ppN = &m_table[index];
329         while ((pN != nullptr) && !KeyFuncs::Equals(k, pN->m_key))
330         {
331             ppN = &pN->m_next;
332             pN  = pN->m_next;
333         }
334         if (pN != nullptr)
335         {
336             *ppN = pN->m_next;
337             m_tableCount--;
338             Node::operator delete(pN, m_alloc);
339             return true;
340         }
341         else
342         {
343             return false;
344         }
345     }
346
347     //------------------------------------------------------------------------
348     // RemoveAll: Remove all keys and their associated values.
349     //
350     // Notes:
351     //    This also frees all the memory owned by the table.
352     //
353     void RemoveAll()
354     {
355         for (unsigned i = 0; i < m_tableSizeInfo.prime; i++)
356         {
357             for (Node* pN = m_table[i]; pN != nullptr;)
358             {
359                 Node* pNext = pN->m_next;
360                 Node::operator delete(pN, m_alloc);
361                 pN = pNext;
362             }
363         }
364         m_alloc->Free(m_table);
365
366         m_table         = nullptr;
367         m_tableSizeInfo = JitPrimeInfo();
368         m_tableCount    = 0;
369         m_tableMax      = 0;
370
371         return;
372     }
373
374     // Get an iterator to the first key in the table.
375     KeyIterator Begin() const
376     {
377         KeyIterator i(this, TRUE);
378         return i;
379     }
380
381     // Get an iterator following the last key in the table.
382     KeyIterator End() const
383     {
384         return KeyIterator(this, FALSE);
385     }
386
387     // Get the number of keys currently stored in the table.
388     unsigned GetCount() const
389     {
390         return m_tableCount;
391     }
392
393     // Get the allocator used by this hash table.
394     Allocator* GetAllocator()
395     {
396         return m_alloc;
397     }
398
399 private:
400     struct Node;
401
402     //------------------------------------------------------------------------
403     // GetIndexForKey: Get the bucket index for the specified key.
404     //
405     // Arguments:
406     //    k - the key
407     //
408     // Return Value:
409     //    A bucket index
410     //
411     unsigned GetIndexForKey(Key k) const
412     {
413         unsigned hash = KeyFuncs::GetHashCode(k);
414
415         unsigned index = m_tableSizeInfo.magicNumberRem(hash);
416
417         return index;
418     }
419
420     //------------------------------------------------------------------------
421     // FindNode: Return a pointer to the node having the specified key, if any.
422     //
423     // Arguments:
424     //    k - the key
425     //
426     // Return Value:
427     //    A pointer to the node or `nullptr` if the key is not found.
428     //
429     Node* FindNode(Key k) const
430     {
431         if (m_tableSizeInfo.prime == 0)
432         {
433             return nullptr;
434         }
435
436         unsigned index = GetIndexForKey(k);
437
438         Node* pN = m_table[index];
439         if (pN == nullptr)
440         {
441             return nullptr;
442         }
443
444         // Otherwise...
445         while ((pN != nullptr) && !KeyFuncs::Equals(k, pN->m_key))
446         {
447             pN = pN->m_next;
448         }
449
450         assert((pN == nullptr) || KeyFuncs::Equals(k, pN->m_key));
451
452         // If pN != nullptr, it's the node for the key, else the key isn't mapped.
453         return pN;
454     }
455
456     //------------------------------------------------------------------------
457     // Grow: Increase the size of the bucket table.
458     //
459     // Notes:
460     //    The new size is computed based on the current population, growth factor,
461     //    and maximum density factor.
462     //
463     void Grow()
464     {
465         unsigned newSize =
466             (unsigned)(m_tableCount * Behavior::s_growth_factor_numerator / Behavior::s_growth_factor_denominator *
467                        Behavior::s_density_factor_denominator / Behavior::s_density_factor_numerator);
468
469         if (newSize < Behavior::s_minimum_allocation)
470         {
471             newSize = Behavior::s_minimum_allocation;
472         }
473
474         // handle potential overflow
475         if (newSize < m_tableCount)
476         {
477             Behavior::NoMemory();
478         }
479
480         Reallocate(newSize);
481     }
482
483     //------------------------------------------------------------------------
484     // CheckGrowth: Check if the maximum hashtable density has been reached
485     // and increase the size of the bucket table if necessary.
486     //
487     void CheckGrowth()
488     {
489         if (m_tableCount == m_tableMax)
490         {
491             Grow();
492         }
493     }
494
495 public:
496     //------------------------------------------------------------------------
497     // CheckGrowth: Replace the bucket table with a larger one and copy all nodes
498     // from the existing bucket table.
499     //
500     // Notes:
501     //    The new size must be large enough to hold all existing keys in
502     //    the table without exceeding the density. Note that the actual
503     //    table size must always be a prime number; the specified size
504     //    will be increased to the next prime if necessary.
505     //
506     void Reallocate(unsigned newTableSize)
507     {
508         assert(newTableSize >=
509                (GetCount() * Behavior::s_density_factor_denominator / Behavior::s_density_factor_numerator));
510
511         // Allocation size must be a prime number.  This is necessary so that hashes uniformly
512         // distribute to all indices, and so that chaining will visit all indices in the hash table.
513         JitPrimeInfo newPrime = NextPrime(newTableSize);
514         newTableSize          = newPrime.prime;
515
516         Node** newTable = (Node**)m_alloc->ArrayAlloc(newTableSize, sizeof(Node*));
517
518         for (unsigned i = 0; i < newTableSize; i++)
519         {
520             newTable[i] = nullptr;
521         }
522
523         // Move all entries over to new table (re-using the Node structures.)
524
525         for (unsigned i = 0; i < m_tableSizeInfo.prime; i++)
526         {
527             Node* pN = m_table[i];
528             while (pN != nullptr)
529             {
530                 Node* pNext = pN->m_next;
531
532                 unsigned newIndex  = newPrime.magicNumberRem(KeyFuncs::GetHashCode(pN->m_key));
533                 pN->m_next         = newTable[newIndex];
534                 newTable[newIndex] = pN;
535
536                 pN = pNext;
537             }
538         }
539
540         if (m_table != nullptr)
541         {
542             m_alloc->Free(m_table);
543         }
544
545         m_table         = newTable;
546         m_tableSizeInfo = newPrime;
547         m_tableMax =
548             (unsigned)(newTableSize * Behavior::s_density_factor_numerator / Behavior::s_density_factor_denominator);
549     }
550
551     // For iteration, we use a pattern similar to the STL "forward
552     // iterator" pattern.  It basically consists of wrapping an
553     // "iteration variable" in an object, and providing pointer-like
554     // operators on the iterator. Example usage:
555     //
556     // for (JitHashTable::KeyIterator iter = foo->Begin(), end = foo->End(); !iter.Equal(end); iter++)
557     // {
558     //      // use foo, iter.
559     // }
560     // iter.Get() will yield (a reference to) the
561     // current key.  It will assert the equivalent of "iter != end."
562     class KeyIterator
563     {
564     private:
565         friend class JitHashTable;
566
567         Node**   m_table;
568         Node*    m_node;
569         unsigned m_tableSize;
570         unsigned m_index;
571
572     public:
573         //------------------------------------------------------------------------
574         // KeyIterator: Construct an iterator for the specified JitHashTable.
575         //
576         // Arguments:
577         //    hash  - the hashtable
578         //    begin - `true` to construct an "begin" iterator,
579         //            `false` to construct an "end" iterator
580         //
581         KeyIterator(const JitHashTable* hash, BOOL begin)
582             : m_table(hash->m_table)
583             , m_node(nullptr)
584             , m_tableSize(hash->m_tableSizeInfo.prime)
585             , m_index(begin ? 0 : m_tableSize)
586         {
587             if (begin && (hash->m_tableCount > 0))
588             {
589                 assert(m_table != nullptr);
590                 while ((m_index < m_tableSize) && (m_table[m_index] == nullptr))
591                 {
592                     m_index++;
593                 }
594
595                 if (m_index >= m_tableSize)
596                 {
597                     return;
598                 }
599                 else
600                 {
601                     m_node = m_table[m_index];
602                 }
603                 assert(m_node != nullptr);
604             }
605         }
606
607         //------------------------------------------------------------------------
608         // Get: Get a reference to this iterator's key.
609         //
610         // Return Value:
611         //    A reference to this iterator's key.
612         //
613         // Assumptions:
614         //    This must not be the "end" iterator.
615         //
616         const Key& Get() const
617         {
618             assert(m_node != nullptr);
619
620             return m_node->m_key;
621         }
622
623         //------------------------------------------------------------------------
624         // GetValue: Get a reference to this iterator's value.
625         //
626         // Return Value:
627         //    A reference to this iterator's value.
628         //
629         // Assumptions:
630         //    This must not be the "end" iterator.
631         //
632         Value& GetValue() const
633         {
634             assert(m_node != nullptr);
635
636             return m_node->m_val;
637         }
638
639         //------------------------------------------------------------------------
640         // SetValue: Assign a new value to this iterator's key
641         //
642         // Arguments:
643         //    value - the value to assign
644         //
645         // Assumptions:
646         //    This must not be the "end" iterator.
647         //
648         void SetValue(const Value& value) const
649         {
650             assert(m_node != nullptr);
651
652             m_node->m_val = value;
653         }
654
655         //------------------------------------------------------------------------
656         // Next: Advance the iterator to the next node.
657         //
658         // Notes:
659         //    Advancing the end iterator has no effect.
660         //
661         void Next()
662         {
663             if (m_node != nullptr)
664             {
665                 m_node = m_node->m_next;
666                 if (m_node != nullptr)
667                 {
668                     return;
669                 }
670
671                 // Otherwise...
672                 m_index++;
673             }
674             while ((m_index < m_tableSize) && (m_table[m_index] == nullptr))
675             {
676                 m_index++;
677             }
678
679             if (m_index >= m_tableSize)
680             {
681                 m_node = nullptr;
682                 return;
683             }
684             else
685             {
686                 m_node = m_table[m_index];
687             }
688             assert(m_node != nullptr);
689         }
690
691         // Return `true` if the specified iterator has the same position as this iterator
692         bool Equal(const KeyIterator& i) const
693         {
694             return i.m_node == m_node;
695         }
696
697         // Advance the iterator to the next node
698         void operator++()
699         {
700             Next();
701         }
702
703         // Advance the iterator to the next node
704         void operator++(int)
705         {
706             Next();
707         }
708     };
709
710     //------------------------------------------------------------------------
711     // operator[]: Get a reference to the value associated with the specified key.
712     //
713     // Arguments:
714     //    k - the key
715     //
716     // Return Value:
717     //    A reference to the value associated with the specified key.
718     //
719     // Notes:
720     //    The specified key must exist.
721     //
722     Value& operator[](Key k) const
723     {
724         Value* p = LookupPointer(k);
725         assert(p);
726         return *p;
727     }
728
729 private:
730     //------------------------------------------------------------------------
731     // NextPrime: Get a prime number greater than or equal to the specified number.
732     //
733     // Arguments:
734     //    number - the minimum value
735     //
736     // Return Value:
737     //    A prime number.
738     //
739     static JitPrimeInfo NextPrime(unsigned number)
740     {
741         for (int i = 0; i < (int)(_countof(jitPrimeInfo)); i++)
742         {
743             if (jitPrimeInfo[i].prime >= number)
744             {
745                 return jitPrimeInfo[i];
746             }
747         }
748
749         // overflow
750         Behavior::NoMemory();
751     }
752
753     // The node type.
754     struct Node
755     {
756         Node* m_next; // Assume that the alignment requirement of Key and Value are no greater than Node*,
757                       // so put m_next first to avoid unnecessary padding.
758         Key   m_key;
759         Value m_val;
760
761         template <class... Args>
762         Node(Node* next, Key k, Args&&... args) : m_next(next), m_key(k), m_val(jitstd::forward<Args>(args)...)
763         {
764         }
765
766         void* operator new(size_t sz, Allocator* alloc)
767         {
768             return alloc->Alloc(sz);
769         }
770
771         void operator delete(void* p, Allocator* alloc)
772         {
773             alloc->Free(p);
774         }
775     };
776
777     // Instance members
778     Allocator*   m_alloc;         // Allocator to use in this table.
779     Node**       m_table;         // pointer to table
780     JitPrimeInfo m_tableSizeInfo; // size of table (a prime) and information about it
781     unsigned     m_tableCount;    // number of elements in table
782     unsigned     m_tableMax;      // maximum occupied count
783 };
784
785 // Commonly used KeyFuncs types:
786
787 // Base class for types whose equality function is the same as their "==".
788 template <typename T>
789 struct JitKeyFuncsDefEquals
790 {
791     static bool Equals(const T& x, const T& y)
792     {
793         return x == y;
794     }
795 };
796
797 template <typename T>
798 struct JitPtrKeyFuncs : public JitKeyFuncsDefEquals<const T*>
799 {
800 public:
801     static unsigned GetHashCode(const T* ptr)
802     {
803         // Using the lower 32 bits of a pointer as a hashcode should be good enough.
804         // In fact, this should result in an unique hash code unless we allocate
805         // more than 4 gigabytes or if the virtual address space is fragmented.
806         return static_cast<unsigned>(reinterpret_cast<uintptr_t>(ptr));
807     }
808 };
809
810 template <typename T> // Must be coercible to "unsigned" with no loss of information.
811 struct JitSmallPrimitiveKeyFuncs : public JitKeyFuncsDefEquals<T>
812 {
813     static unsigned GetHashCode(const T& val)
814     {
815         return static_cast<unsigned>(val);
816     }
817 };
818
819 template <typename T> // Assumed to be of size sizeof(UINT64).
820 struct JitLargePrimitiveKeyFuncs : public JitKeyFuncsDefEquals<T>
821 {
822     static unsigned GetHashCode(const T val)
823     {
824         // A static cast when T is a float or a double converts the value (i.e. 0.25 converts to 0)
825         //
826         // Instead we want to use all of the bits of a float to create the hash value
827         // So we cast the address of val to a pointer to an equivalent sized unsigned int
828         // This allows us to read the actual bit representation of a float type
829         //
830         // We can't read beyond the end of val, so we use sizeof(T) to determine
831         // exactly how many bytes to read
832         //
833         if (sizeof(T) == 8)
834         {
835             // cast &val to (UINT64 *) then deref to get the bits
836             UINT64 asUINT64 = *(reinterpret_cast<const UINT64*>(&val));
837
838             // Get the upper and lower 32-bit values from the 64-bit value
839             UINT32 upper32 = static_cast<UINT32>(asUINT64 >> 32);
840             UINT32 lower32 = static_cast<UINT32>(asUINT64 & 0xFFFFFFFF);
841
842             // Exclusive-Or the upper32 and the lower32 values
843             return static_cast<unsigned>(upper32 ^ lower32);
844         }
845         else if (sizeof(T) == 4)
846         {
847             // cast &val to (UINT32 *) then deref to get the bits
848             UINT32 asUINT32 = *(reinterpret_cast<const UINT32*>(&val));
849
850             // Just return the 32-bit value
851             return static_cast<unsigned>(asUINT32);
852         }
853         else if ((sizeof(T) == 2) || (sizeof(T) == 1))
854         {
855             // For small sizes we must have an integer type
856             // so we can just use the static_cast.
857             //
858             return static_cast<unsigned>(val);
859         }
860         else
861         {
862             // Only support Hashing for types that are 8,4,2 or 1 bytes in size
863             assert(!"Unsupported size");
864             return static_cast<unsigned>(val); // compile-time error here when we have a illegal size
865         }
866     }
867 };