gKitGL
|
00001 00002 #ifndef _GK_NAME_H 00003 #define _GK_NAME_H 00004 00005 #include <string> 00006 #include <cstring> 00007 #include <cassert> 00008 00009 00010 namespace gk { 00011 00012 #define GK_NAME_MAX 40 00013 #define GK_NAME_HASH_SEED 1 00014 00015 //! representation d'un identifiant par une chaine de caracteres et / ou un index. 00016 //! longueur limitee a 40 caracteres. 00017 //! les comparaisons / recherches sur la chaine de caracteres sont remplacees par une comparaison sur une valeur de hachage. 00018 class Name 00019 { 00020 #ifndef GK_NAME_NOSTRING 00021 char m_name[GK_NAME_MAX]; //!< chaine de caracteres. 00022 #endif 00023 00024 unsigned int m_hash; //!< hachage de la chaine de caracteres. 00025 int m_id; //!< index / identifiant numerique 00026 00027 //! calcul de la valeur de hacahge par l'algorithme murmurhash2 cf http://sites.google.com/site/murmurhash/ 00028 static 00029 unsigned int murmur2( const char *string, const int length, const unsigned int seed ) 00030 { 00031 // 'm' and 'r' are mixing constants generated offline. 00032 // They're not really 'magic', they just happen to work well. 00033 const unsigned int m = 0x5bd1e995; 00034 const int r = 24; 00035 00036 // Initialize the hash to a 'random' value 00037 unsigned int h = seed ^ length; 00038 int len= length; 00039 00040 // Mix 4 bytes at a time into the hash 00041 const unsigned char *data = (const unsigned char *) string; 00042 while(len >= 4) 00043 { 00044 unsigned int k = * (const unsigned int *) data; 00045 00046 k *= m; 00047 k ^= k >> r; 00048 k *= m; 00049 00050 h *= m; 00051 h ^= k; 00052 00053 data += 4; 00054 len -= 4; 00055 } 00056 00057 // Handle the last few bytes of the input array 00058 switch(len) 00059 { 00060 case 3: h ^= data[2] << 16; 00061 case 2: h ^= data[1] << 8; 00062 case 1: h ^= data[0]; 00063 h *= m; 00064 }; 00065 00066 // Do a few final mixes of the hash to ensure the last few 00067 // bytes are well-incorporated. 00068 h ^= h >> 13; 00069 h *= m; 00070 h ^= h >> 15; 00071 00072 return h; 00073 } 00074 00075 //! utilisation interne. 00076 void hash( const char *string ) 00077 { 00078 m_hash= murmur2(string, GK_NAME_MAX, GK_NAME_HASH_SEED); 00079 } 00080 00081 public: 00082 //! constructeur par defaut. 00083 Name( ) 00084 : 00085 m_hash(0), 00086 m_id(-1) 00087 { 00088 #ifndef GK_NAME_NOSTRING 00089 m_name[0]= 0; 00090 #endif 00091 } 00092 00093 //! constructeur. identifiant numerique. 00094 Name( const int id ) 00095 : 00096 m_hash(0), 00097 m_id(id) 00098 { 00099 #ifndef GK_NAME_NOSTRING 00100 m_name[0]= 0; 00101 #endif 00102 } 00103 00104 //! constructeur. chaine de caracteres. 00105 Name( const char *string ) 00106 : 00107 m_hash(0), 00108 m_id(-1) 00109 { 00110 #ifndef GK_NAME_NOSTRING 00111 strncpy(m_name, string, GK_NAME_MAX); 00112 m_name[GK_NAME_MAX -1]= 0; 00113 hash(m_name); 00114 00115 #else 00116 char name[GK_NAME_MAX]; 00117 strncpy(name, string, GK_NAME_MAX); 00118 name[GK_NAME_MAX -1]= 0; 00119 hash(name); 00120 #endif 00121 } 00122 00123 //! constructeur. chaine de caracteres c++. 00124 Name( const std::string& string ) 00125 : 00126 m_hash(0), 00127 m_id(-1) 00128 { 00129 #ifndef GK_NAME_NOSTRING 00130 strncpy(m_name, string.c_str(), GK_NAME_MAX); 00131 m_name[GK_NAME_MAX -1]= 0; 00132 hash(m_name); 00133 00134 #else 00135 char name[GK_NAME_MAX]; 00136 strncpy(name, string.c_str(), GK_NAME_MAX); 00137 name[GK_NAME_MAX -1]= 0; 00138 hash(name); 00139 #endif 00140 } 00141 00142 //! constructeur complet (chaine + id). 00143 Name( const char *string, const int id ) 00144 : 00145 m_hash(0), 00146 m_id(id) 00147 { 00148 #ifndef GK_NAME_NOSTRING 00149 strncpy(m_name, string, GK_NAME_MAX); 00150 m_name[GK_NAME_MAX -1]= 0; 00151 hash(m_name); 00152 00153 #else 00154 char name[GK_NAME_MAX]; 00155 strncpy(name, string, GK_NAME_MAX); 00156 name[GK_NAME_MAX -1]= 0; 00157 hash(name); 00158 #endif 00159 } 00160 00161 //! constructeur. (chaine c++ + id). 00162 Name( const std::string& string, const int id ) 00163 : 00164 m_hash(0), 00165 m_id(id) 00166 { 00167 #ifndef GK_NAME_NOSTRING 00168 strncpy(m_name, string.c_str(), GK_NAME_MAX); 00169 m_name[GK_NAME_MAX -1]= 0; 00170 hash(m_name); 00171 00172 #else 00173 char name[GK_NAME_MAX]; 00174 strncpy(name, string.c_str(), GK_NAME_MAX); 00175 name[GK_NAME_MAX -1]= 0; 00176 hash(name); 00177 #endif 00178 } 00179 00180 //! constructeur. 00181 Name( const Name& b ) 00182 { 00183 #ifndef GK_NAME_NOSTRING 00184 strcpy(m_name, b.m_name); 00185 #endif 00186 m_hash= b.m_hash; 00187 m_id= b.m_id; 00188 } 00189 00190 //! affectation. 00191 Name& operator=( const Name&b ) 00192 { 00193 #ifndef GK_NAME_NOSTRING 00194 strcpy(m_name, b.m_name); 00195 #endif 00196 m_hash= b.m_hash; 00197 m_id= b.m_id; 00198 return *this; 00199 } 00200 00201 //! renvoie la valeur de hachage. 00202 unsigned int hash( ) const 00203 { 00204 return m_hash; 00205 } 00206 00207 //! renvoie l'identifiant numerique. 00208 unsigned int id( ) const 00209 { 00210 return m_id; 00211 } 00212 00213 //! renvoie la chaine de caracteres, si definie. 00214 const char *c_str( ) const 00215 { 00216 #ifndef GK_NAME_NOSTRING 00217 return m_name; 00218 #else 00219 return "(Name NOSTRING)"; 00220 #endif 00221 } 00222 00223 //! renvoie la chaine de caracteres, si definie. 00224 const char *c_str( ) 00225 { 00226 #ifndef GK_NAME_NOSTRING 00227 return m_name; 00228 #else 00229 return "(Name NOSTRING)"; 00230 #endif 00231 } 00232 00233 //! comparaisons. 00234 friend bool operator==( const Name& a, const Name& b ); 00235 //! comparaisons. 00236 friend bool operator!=( const Name& a, const Name& b ); 00237 //! comparaisons. 00238 friend bool operator<( const Name& a, const Name& b ); 00239 //! comparaisons. 00240 friend bool operator>( const Name& a, const Name& b ); 00241 //! comparaisons. 00242 friend int compare( const Name& a, const Name& b ); 00243 00244 //! calcule la valeur de hachage d'une chaine de caractere quelconque. 00245 static 00246 unsigned int getHash( const char * string ) 00247 { 00248 return murmur2(string, strlen(string), GK_NAME_HASH_SEED); 00249 } 00250 00251 //! calcule la valeur de hachage d'une chaine de caractere quelconque. 00252 static 00253 unsigned int getHash( const std::string& string ) 00254 { 00255 return murmur2(string.c_str(), string.size(), GK_NAME_HASH_SEED); 00256 } 00257 00258 //! \todo construction incrementale a partir de plusieurs chaines / cles intermediaires, pour la construction des identifiants mesh, mesh_material, shader, etc ? 00259 //! cf murmurhash2a.cpp et ecrire les operateurs + << = += ? au lieu des fonctions utilisees dans l'exemple. 00260 }; 00261 00262 inline 00263 bool operator==( const Name& a, const Name& b ) 00264 { 00265 if(a.m_id < 0 || b.m_id < 0) 00266 { 00267 #ifdef GK_NAME_NOSTRING 00268 return (a.m_hash == b.m_hash); 00269 #else 00270 return (a.m_hash == b.m_hash) && (strcmp(a.m_name, b.m_name) == 0); 00271 #endif 00272 } 00273 else 00274 { 00275 return (a.m_id == b.m_id); 00276 } 00277 } 00278 00279 inline 00280 bool operator!=( const Name& a, const Name& b ) 00281 { 00282 if(a.m_id < 0 || b.m_id < 0) 00283 return (a.m_hash != b.m_hash); 00284 else 00285 return (a.m_id != b.m_id); 00286 } 00287 00288 inline 00289 bool operator>( const Name& a, const Name& b ) 00290 { 00291 if(a.m_id < 0 || b.m_id < 0) 00292 return (a.m_hash > b.m_hash); 00293 else 00294 return (a.m_id > b.m_id); 00295 } 00296 00297 inline 00298 bool operator<( const Name& a, const Name& b ) 00299 { 00300 if(a.m_id < 0 || b.m_id < 0) 00301 return (a.m_hash < b.m_hash); 00302 else 00303 return (a.m_id < b.m_id);} 00304 00305 inline 00306 int compare( const Name& a, const Name& b ) 00307 { 00308 if(a.m_id < 0 || b.m_id < 0) 00309 { 00310 if(a.m_hash < b.m_hash) 00311 return -1; 00312 else if(a.m_hash > b.m_hash) 00313 return 1; 00314 else 00315 #ifdef GK_NAME_NOSTRING 00316 return 0; 00317 #else 00318 return strcmp(a.m_name, b.m_name); 00319 #endif 00320 } 00321 else 00322 { 00323 if(a.m_id < b.m_id) 00324 return -1; 00325 else if(a.m_id > b.m_id) 00326 return 1; 00327 else 00328 return 0; 00329 } 00330 } 00331 00332 } 00333 00334 #endif 00335 00336 00337 #if 0 00338 // version template, a tester 00339 // from http://www.humus.name/index.php?page=Comments&ID=296&start=24 00340 00341 class StringHash 00342 { 00343 private: 00344 uint32_t m_val; 00345 00346 template<size_t N> inline 00347 uint32_t _Hash(const char (&str)[N]) const 00348 { 00349 typedef const char (&truncated_str)[N-1]; 00350 return str[N-1] + 65599 * _Hash((truncated_str)str); 00351 } 00352 00353 inline 00354 uint32_t _Hash(const char (&str)[2]) const { return str[1] + 65599 * str[0]; } 00355 00356 public: 00357 template <size_t N> StringHash(const char (&str)[N]) { m_val = _Hash(str); } 00358 inline operator uint32_t() const { return m_val; } 00359 }; 00360 00361 00362 00363 00364 class StringHash 00365 { 00366 unsigned m_val; 00367 00368 template<size_t N> 00369 __forceinline unsigned _Hash(const char (&str)[N]) 00370 { 00371 typedef const char (&truncated_str)[N-4]; 00372 return str[N-1] + 65599*(str[N-2] + 65599*(str[N-3] + 65599 * (str[N-4] + 65599*_Hash((truncated_str)str)))); 00373 } 00374 00375 __forceinline 00376 unsigned _Hash(const char (&str)[4]) 00377 { 00378 typedef const char (&truncated_str)[3]; 00379 return str[3] + 65599 * _Hash((truncated_str)str); 00380 } 00381 00382 __forceinline 00383 unsigned _Hash(const char (&str)[3]) 00384 { 00385 typedef const char (&truncated_str)[2]; 00386 return str[2] + 65599 * _Hash((truncated_str)str); 00387 } 00388 00389 __forceinline unsigned _Hash(const char (&str)[2]) { return str[1] + 65599 * str[0]; } 00390 __forceinline unsigned _Hash(const char (&str)[1]) { return str[0]; } 00391 00392 public: 00393 template <size_t N> __forceinline StringHash(const char (&str)[N]) { m_val = _Hash(str); } 00394 operator unsigned() { return m_val; } 00395 }; 00396 00397 int _tmain(int argc, _TCHAR* argv[]) 00398 { 00399 #define STRING_262 "The a value 1, The a value 2,...etc" 00400 printf("a hash = %x\n", StringHash(STRING_262) ); 00401 printf("b hash = %x\n", StringHash("The b value" ); 00402 printf("a hash 2 = %x\n", StringHash(STRING_262) ); 00403 return 0; 00404 } 00405 00406 #endif