Created
July 17, 2012 19:27
-
-
Save nlguillemot/3131438 to your computer and use it in GitHub Desktop.
Compile-time hashed strings with unit test
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <cstdint> | |
// if HASHEDSTRING_USE_CONSTEXPR is defined, a recursive constexpr hashing algorithm will be used. | |
// otherwise, an iterative runtime hashing algorithm will be used. | |
#define HASHEDSTRING_USE_CONSTEXPR | |
// do not touch this block of preprocessor. | |
#ifdef HASHEDSTRING_USE_CONSTEXPR | |
#define HASHEDSTRING_CONSTEXPR_IMPL constexpr | |
#else | |
#define HASHEDSTRING_CONSTEXPR_IMPL | |
#endif | |
namespace vik | |
{ | |
// encapsulates hashed strings | |
// will try to remember the original string in debug builds. | |
// in release builds, will not store the string at all. | |
// strings are hashed at compile time whenever possible using constexpr, if the HASHEDSTRING_USE_CONSTEXPR flag is defined. | |
class HashedString | |
{ | |
private: | |
typedef uint32_t HashType; | |
public: | |
friend HASHEDSTRING_CONSTEXPR_IMPL HashType _hashString(const char* str); | |
friend HASHEDSTRING_CONSTEXPR_IMPL HashType _hashStringRecursive(HashType hash, const char* str); | |
// Hashes the passed in string and stores the hash | |
// in debug builds, the original string pointer will also be stored to be accessed with getDebugString() | |
inline explicit HASHEDSTRING_CONSTEXPR_IMPL HashedString(const char* str); | |
// in debug builds, will return the originally hashed string. | |
// in debug builds, causes undefined behaviour if the string originally used to construct the hash no longer exists. | |
// in release builds, will return an empty string. Should not call this function in release builds. | |
inline const char* getReverseHash() const; | |
// compares hash by equality | |
inline constexpr bool operator==(const HashedString& other) const; | |
inline constexpr bool operator!=(const HashedString& other) const; | |
// compares hash in terms of order to allow efficient use with std::less<T> as a Compare function in std::maps | |
inline constexpr bool operator<(const HashedString& other) const; | |
// add more comparison operators as they are needed. Always compare with the hash, not the reverse hash. | |
private: | |
// reverse hash only exists in debug build | |
#ifdef _DEBUG | |
const char* debugReverseHash; | |
#endif | |
HashType hash; | |
}; | |
// performs a compile time recursive string hash using the djb2 algorithm explained here: http://www.cse.yorku.ca/~oz/hash.html | |
// To hash a string, do not call these functions. Instead, construct a HashedString with the string passed as an argument to the constructor. | |
HASHEDSTRING_CONSTEXPR_IMPL HashedString::HashType _hashStringRecursive(HashedString::HashType hash, const char* str) | |
{ | |
return ( !*str ? hash : | |
_hashStringRecursive(((hash << 5) + hash) + *str, str + 1)); | |
} | |
// performs a compile time string hash | |
HASHEDSTRING_CONSTEXPR_IMPL HashedString::HashType _hashString(const char* str) | |
{ | |
#ifdef HASHEDSTRING_USE_CONSTEXPR | |
return ( !str ? 0 : | |
_hashStringRecursive(5381, str)); | |
#else | |
HashType hash = 5381; | |
int x; | |
while ( (x = *str++) ) | |
{ | |
hash += ((hash << 5) + hash) + x; | |
} | |
return hash; | |
#endif | |
} | |
HASHEDSTRING_CONSTEXPR_IMPL HashedString::HashedString(const char* str): | |
#ifdef _DEBUG | |
debugReverseHash(str), | |
#endif | |
hash(_hashString(str)) | |
{ | |
} | |
const char* HashedString::getReverseHash() const | |
{ | |
#ifdef _DEBUG | |
return debugReverseHash; | |
#else | |
return ""; | |
#endif | |
} | |
bool constexpr HashedString::operator==(const HashedString& other) const | |
{ | |
return hash == other.hash; | |
} | |
bool constexpr HashedString::operator!=(const HashedString& other) const | |
{ | |
return hash != other.hash; | |
} | |
bool constexpr HashedString::operator<(const HashedString& other) const | |
{ | |
return hash < other.hash; | |
} | |
} // end namespace vik | |
static_assert(vik::HashedString("foo") != vik::HashedString("bar"), "compare different hashed string by key"); | |
static_assert(vik::HashedString("foo") == vik::HashedString("foo"), "compare identical strings by key"); | |
static_assert(vik::HashedString("bar") < vik::HashedString("foo"), "compare strings by key ordering"); | |
int main() | |
{ | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
compiles with gcc 4.6.3 with "g++ HashedString.cpp -std=c++0x"