| 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 | // MetaDataHash.h -- Meta data hash data structures. |
| 6 | // |
| 7 | |
| 8 | // |
| 9 | // Used by Emitters and by E&C. |
| 10 | // |
| 11 | //***************************************************************************** |
| 12 | #ifndef _MetaDataHash_h_ |
| 13 | #define _MetaDataHash_h_ |
| 14 | |
| 15 | #if _MSC_VER >= 1100 |
| 16 | # pragma once |
| 17 | #endif |
| 18 | |
| 19 | #include "utilcode.h" |
| 20 | |
| 21 | |
| 22 | #define REHASH_THREADSHOLD 3 |
| 23 | |
| 24 | |
| 25 | //***************************************************************************** |
| 26 | // A hash entry list item. |
| 27 | //***************************************************************************** |
| 28 | struct TOKENHASHENTRY |
| 29 | { |
| 30 | mdToken tok; |
| 31 | ULONG ulHash; |
| 32 | ULONG iNext; |
| 33 | }; |
| 34 | |
| 35 | //***************************************************************************** |
| 36 | // The following is a hash class definition used for hashing MemberDef. The difference |
| 37 | // from the hash table above is because it is expansive to retrieve the parent for MemberDef. |
| 38 | // |
| 39 | //***************************************************************************** |
| 40 | struct MEMBERDEFHASHENTRY |
| 41 | { |
| 42 | mdToken tok; |
| 43 | mdToken tkParent; |
| 44 | ULONG ulHash; |
| 45 | ULONG iNext; |
| 46 | }; |
| 47 | |
| 48 | |
| 49 | //***************************************************************************** |
| 50 | // This class is used to create transient indexes for meta data structures. |
| 51 | // This class is generic; one must override it to provide hashing and |
| 52 | // accessor methods for your specific record type. It can start out on top |
| 53 | // of malloc with a small memory footprint, and as you get larger, it must |
| 54 | // be capable of rehashing. |
| 55 | //***************************************************************************** |
| 56 | template <class Entry> class CMetaDataHashTemplate |
| 57 | { |
| 58 | public: |
| 59 | CMetaDataHashTemplate() |
| 60 | { |
| 61 | m_rgBuckets = 0; |
| 62 | m_cItems = 0; |
| 63 | m_iBuckets = 0; |
| 64 | } |
| 65 | |
| 66 | ~CMetaDataHashTemplate() |
| 67 | { |
| 68 | // Free the bucket list. |
| 69 | if (m_rgBuckets) |
| 70 | { |
| 71 | delete [] m_rgBuckets; |
| 72 | m_rgBuckets = 0; |
| 73 | m_cItems = 0; |
| 74 | m_iBuckets = 0; |
| 75 | } |
| 76 | } |
| 77 | |
| 78 | //***************************************************************************** |
| 79 | // Called to allocate the hash table entries so that new data may be added. |
| 80 | //***************************************************************************** |
| 81 | HRESULT NewInit( // Return status. |
| 82 | int iBuckets=17) // How many buckets you want. |
| 83 | { |
| 84 | m_rgBuckets = new (nothrow) int[iBuckets]; |
| 85 | if (!m_rgBuckets) |
| 86 | return (OutOfMemory()); |
| 87 | m_iBuckets = iBuckets; |
| 88 | memset(m_rgBuckets, ~0, sizeof(int) * iBuckets); |
| 89 | return (S_OK); |
| 90 | } |
| 91 | |
| 92 | //***************************************************************************** |
| 93 | // Add new items to the hash list. |
| 94 | //***************************************************************************** |
| 95 | Entry *Add( // Pointer to element to write to. |
| 96 | ULONG iHash) // Hash value of entry to add. |
| 97 | { |
| 98 | Entry *p = 0; |
| 99 | HRESULT hr; |
| 100 | |
| 101 | int iBucket = iHash % m_iBuckets; |
| 102 | |
| 103 | if (m_cItems > REHASH_THREADSHOLD * m_iBuckets) |
| 104 | { |
| 105 | hr = ReHash(); |
| 106 | if (FAILED(hr)) |
| 107 | return (0); |
| 108 | iBucket = iHash % m_iBuckets; |
| 109 | } |
| 110 | |
| 111 | // Add a new item pointer. |
| 112 | p = m_Heap.Append(); |
| 113 | if (!p) |
| 114 | return (0); |
| 115 | |
| 116 | // Chain the new item to the front of the heap. |
| 117 | p->iNext = m_rgBuckets[iBucket]; |
| 118 | p->ulHash = iHash; |
| 119 | m_cItems++; |
| 120 | m_rgBuckets[iBucket] = m_Heap.ItemIndex(p); |
| 121 | return (p); |
| 122 | } |
| 123 | |
| 124 | |
| 125 | //***************************************************************************** |
| 126 | // Grow the hash table |
| 127 | //***************************************************************************** |
| 128 | HRESULT ReHash() |
| 129 | { |
| 130 | int *rgBuckets; |
| 131 | int iBuckets; |
| 132 | int iBucket; |
| 133 | int index; |
| 134 | int iCount; |
| 135 | Entry *p = 0; |
| 136 | |
| 137 | iBuckets = m_iBuckets*2 -1; |
| 138 | rgBuckets = new (nothrow) int[iBuckets]; |
| 139 | if (!rgBuckets) |
| 140 | return (OutOfMemory()); |
| 141 | memset(rgBuckets, ~0, sizeof(int) * iBuckets); |
| 142 | |
| 143 | // loop through each of data and rehash them |
| 144 | iCount = m_Heap.Count(); |
| 145 | for (index = 0; index < iCount; index++) |
| 146 | { |
| 147 | // get the hash value of the entry |
| 148 | p = m_Heap.Get(index); |
| 149 | |
| 150 | // rehash the entry |
| 151 | iBucket = p->ulHash % iBuckets; |
| 152 | |
| 153 | // Chain the item to the front of the new heap. |
| 154 | p->iNext = rgBuckets[iBucket]; |
| 155 | rgBuckets[iBucket] = index; |
| 156 | } |
| 157 | |
| 158 | // swap the hash table |
| 159 | delete [] m_rgBuckets; |
| 160 | m_rgBuckets = rgBuckets; |
| 161 | m_iBuckets = iBuckets; |
| 162 | return NOERROR; |
| 163 | |
| 164 | } |
| 165 | |
| 166 | //***************************************************************************** |
| 167 | // Find first/find next node for a chain given the hash. |
| 168 | //***************************************************************************** |
| 169 | Entry *FindFirst( // Return entry. |
| 170 | ULONG iHash, // The hash value for the entry. |
| 171 | int &POS) // Current position. |
| 172 | { |
| 173 | int iBucket = iHash % m_iBuckets; |
| 174 | POS = m_rgBuckets[iBucket]; |
| 175 | return (FindNext(POS)); |
| 176 | } |
| 177 | |
| 178 | Entry *FindNext( // Return entry or 0. |
| 179 | int &POS) // Current location. |
| 180 | { |
| 181 | Entry *p; |
| 182 | |
| 183 | if (POS == ~0) |
| 184 | return (0); |
| 185 | |
| 186 | p = m_Heap.Get(POS); |
| 187 | POS = p->iNext; |
| 188 | return (p); |
| 189 | } |
| 190 | |
| 191 | private: |
| 192 | CDynArray<Entry> m_Heap; // First heap in the list. |
| 193 | int *m_rgBuckets; // Bucket list. |
| 194 | int m_iBuckets; // How many buckets. |
| 195 | int m_cItems; // Number of items in the hash |
| 196 | }; |
| 197 | |
| 198 | |
| 199 | class CMetaDataHashBase : public CMetaDataHashTemplate<TOKENHASHENTRY> |
| 200 | { |
| 201 | }; |
| 202 | |
| 203 | class CMemberDefHash : public CMetaDataHashTemplate<MEMBERDEFHASHENTRY> |
| 204 | { |
| 205 | }; |
| 206 | |
| 207 | #endif // _MetaDataHash_h_ |
| 208 | |