00001
00002
00003
00004
00005
00006
00007 #ifndef SG_HASHTABLE_H
00008 #define SG_HASHTABLE_H
00009
00010 #include "SgHash.h"
00011 #include "SgWrite.h"
00012
00013
00014
00015
00016 template <class DATA>
00017 struct SgHashEntry
00018 {
00019 SgHashEntry()
00020 : m_hash(),
00021 m_data()
00022 { }
00023
00024 SgHashEntry(const SgHashCode& code, const DATA& data)
00025 : m_hash(code),
00026 m_data(data)
00027 { }
00028
00029 SgHashCode m_hash;
00030
00031 DATA m_data;
00032 };
00033
00034
00035
00036
00037 template <class DATA>
00038 class SgHashTable
00039 {
00040 public:
00041
00042 explicit SgHashTable(int maxHash);
00043
00044 ~SgHashTable();
00045
00046
00047
00048
00049
00050 void Age();
00051
00052
00053 void Clear();
00054
00055
00056
00057
00058 bool Lookup(const SgHashCode& code, DATA* data) const;
00059
00060
00061 int MaxHash() const;
00062
00063
00064
00065
00066
00067 bool Store(const SgHashCode& code, const DATA& data);
00068
00069
00070 int NuCollisions() const
00071 {
00072 return m_nuCollisions;
00073 }
00074
00075
00076 int NuStores() const
00077 {
00078 return m_nuStores;
00079 }
00080
00081
00082 int NuLookups() const
00083 {
00084 return m_nuLookups;
00085 }
00086
00087
00088 int NuFound() const
00089 {
00090 return m_nuFound;
00091 }
00092
00093 private:
00094
00095 SgHashEntry<DATA>* m_entry;
00096
00097
00098 int m_maxHash;
00099
00100
00101
00102
00103
00104 mutable int m_nuCollisions;
00105
00106
00107 mutable int m_nuStores;
00108
00109
00110 mutable int m_nuLookups;
00111
00112
00113 mutable int m_nuFound;
00114
00115
00116 SgHashTable(const SgHashTable&);
00117
00118
00119 SgHashTable& operator=(const SgHashTable&);
00120 };
00121
00122 template <class DATA>
00123 SgHashTable<DATA>::SgHashTable(int maxHash)
00124 : m_entry(0),
00125 m_maxHash(maxHash),
00126 m_nuCollisions(0),
00127 m_nuStores(0),
00128 m_nuLookups(0),
00129 m_nuFound(0)
00130 {
00131 m_entry = new SgHashEntry<DATA>[m_maxHash];
00132 Clear();
00133 }
00134
00135 template <class DATA>
00136 SgHashTable<DATA>::~SgHashTable()
00137 {
00138 delete[] m_entry;
00139 }
00140
00141 template <class DATA>
00142 void SgHashTable<DATA>::Age()
00143 {
00144 for (int i = m_maxHash-1; i >= 0; --i)
00145 {
00146 m_entry[i].m_data.AgeData();
00147 }
00148 }
00149
00150 template <class DATA>
00151 void SgHashTable<DATA>::Clear()
00152 {
00153 for (int i = m_maxHash-1; i >= 0; --i)
00154 {
00155 m_entry[i].m_data.Invalidate();
00156 }
00157 }
00158
00159 template <class DATA>
00160 int SgHashTable<DATA>::MaxHash() const
00161 {
00162 return m_maxHash;
00163 }
00164
00165 template <class DATA>
00166 bool SgHashTable<DATA>::Store(const SgHashCode& code, const DATA& data)
00167 {
00168 ++m_nuStores;
00169 int h = code.Hash(m_maxHash);
00170 SgHashEntry<DATA>& entry = m_entry[h];
00171 if (entry.m_data.IsValid() && code != entry.m_hash)
00172 ++m_nuCollisions;
00173 if (! entry.m_data.IsValid() || data.IsBetterThan(entry.m_data))
00174 {
00175 entry.m_hash = code;
00176 entry.m_data = data;
00177 return true;
00178 }
00179 return false;
00180 }
00181
00182 template <class DATA>
00183 bool SgHashTable<DATA>::Lookup(const SgHashCode& code, DATA* data) const
00184 {
00185 ++m_nuLookups;
00186 int h = code.Hash(m_maxHash);
00187 const SgHashEntry<DATA>& entry = m_entry[h];
00188 if (entry.m_data.IsValid() && entry.m_hash == code)
00189 {
00190 *data = entry.m_data;
00191 ++m_nuFound;
00192 return true;
00193 }
00194 return false;
00195 }
00196
00197
00198
00199
00200 template <class DATA>
00201 std::ostream& operator<<(std::ostream& out, const SgHashTable<DATA>& hash)
00202 {
00203 out << "HashTableStatistics:\n"
00204 << SgWriteLabel("Stores") << hash.NuStores() << '\n'
00205 << SgWriteLabel("LookupAttempt") << hash.NuLookups() << '\n'
00206 << SgWriteLabel("LookupSuccess") << hash.NuFound() << '\n'
00207 << SgWriteLabel("Collisions") << hash.NuCollisions() << '\n';
00208 return out;
00209 }
00210
00211 #endif // SG_HASHTABLE_H