gKitGL
Name.h
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
 All Classes Namespaces Functions Variables Typedefs Enumerator Friends