forked from llvm-mirror/llvm
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Hashing.h - utilities for hashing various data types.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@150890 91177308-0d34-0410-b5e6-96231b3b80d8
- Loading branch information
Showing
5 changed files
with
285 additions
and
0 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,180 @@ | ||
//===-- llvm/ADT/Hashing.h - Utilities for hashing --------------*- C++ -*-===// | ||
// | ||
// The LLVM Compiler Infrastructure | ||
// | ||
// This file is distributed under the University of Illinois Open Source | ||
// License. See LICENSE.TXT for details. | ||
// | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// This file defines utilities for computing hash values for various data types. | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#ifndef LLVM_ADT_HASHING_H | ||
#define LLVM_ADT_HASHING_H | ||
|
||
#include "llvm/ADT/ArrayRef.h" | ||
#include "llvm/ADT/StringRef.h" | ||
#include "llvm/Support/AlignOf.h" | ||
#include "llvm/Support/Compiler.h" | ||
#include "llvm/Support/DataTypes.h" | ||
|
||
namespace llvm { | ||
|
||
/// Class to compute a hash value from multiple data fields of arbitrary | ||
/// types. Note that if you are hashing a single data type, such as a | ||
/// string, it may be cheaper to use a hash algorithm that is tailored | ||
/// for that specific data type. | ||
/// Typical Usage: | ||
/// GeneralHash Hash; | ||
/// Hash.add(someValue); | ||
/// Hash.add(someOtherValue); | ||
/// return Hash.finish(); | ||
/// Adapted from MurmurHash2 by Austin Appleby | ||
class GeneralHash { | ||
private: | ||
enum { | ||
M = 0x5bd1e995 | ||
}; | ||
unsigned Hash; | ||
unsigned Count; | ||
public: | ||
GeneralHash(unsigned Seed = 0) : Hash(Seed), Count(0) {} | ||
|
||
/// Add a pointer value. | ||
/// Note: this adds pointers to the hash using sizes and endianness that | ||
/// depend on the host. It doesn't matter however, because hashing on | ||
/// pointer values is inherently unstable. | ||
template<typename T> | ||
GeneralHash& add(const T *PtrVal) { | ||
addBits(&PtrVal, &PtrVal + 1); | ||
return *this; | ||
} | ||
|
||
/// Add an ArrayRef of arbitrary data. | ||
template<typename T> | ||
GeneralHash& add(ArrayRef<T> ArrayVal) { | ||
addBits(ArrayVal.begin(), ArrayVal.end()); | ||
return *this; | ||
} | ||
|
||
/// Add a string | ||
GeneralHash& add(StringRef StrVal) { | ||
addBits(StrVal.begin(), StrVal.end()); | ||
return *this; | ||
} | ||
|
||
/// Add an signed 32-bit integer. | ||
GeneralHash& add(int32_t Data) { | ||
addInt(uint32_t(Data)); | ||
return *this; | ||
} | ||
|
||
/// Add an unsigned 32-bit integer. | ||
GeneralHash& add(uint32_t Data) { | ||
addInt(Data); | ||
return *this; | ||
} | ||
|
||
/// Add an signed 64-bit integer. | ||
GeneralHash& add(int64_t Data) { | ||
addInt(uint64_t(Data)); | ||
return *this; | ||
} | ||
|
||
/// Add an unsigned 64-bit integer. | ||
GeneralHash& add(uint64_t Data) { | ||
addInt(Data); | ||
return *this; | ||
} | ||
|
||
/// Add a float | ||
GeneralHash& add(float Data) { | ||
union { | ||
float D; uint32_t I; | ||
}; | ||
D = Data; | ||
addInt(I); | ||
return *this; | ||
} | ||
|
||
/// Add a double | ||
GeneralHash& add(double Data) { | ||
union { | ||
double D; uint64_t I; | ||
}; | ||
D = Data; | ||
addInt(I); | ||
return *this; | ||
} | ||
|
||
// Do a few final mixes of the hash to ensure the last few | ||
// bytes are well-incorporated. | ||
unsigned finish() { | ||
mix(Count); | ||
Hash ^= Hash >> 13; | ||
Hash *= M; | ||
Hash ^= Hash >> 15; | ||
return Hash; | ||
} | ||
|
||
private: | ||
void mix(uint32_t Data) { | ||
++Count; | ||
Data *= M; | ||
Data ^= Data >> 24; | ||
Data *= M; | ||
Hash *= M; | ||
Hash ^= Data; | ||
} | ||
|
||
// Add a single uint32 value | ||
void addInt(uint32_t Val) { | ||
mix(Val); | ||
} | ||
|
||
// Add a uint64 value | ||
void addInt(uint64_t Val) { | ||
mix(uint32_t(Val >> 32)); | ||
mix(uint32_t(Val)); | ||
} | ||
|
||
template<typename T, bool isAligned> | ||
struct addBitsImpl { | ||
static void add(GeneralHash &Hash, const T *I, const T *E) { | ||
Hash.addUnaligned( | ||
reinterpret_cast<const uint8_t *>(I), | ||
reinterpret_cast<const uint8_t *>(E)); | ||
} | ||
}; | ||
|
||
template<typename T> | ||
struct addBitsImpl<T, true> { | ||
static void add(GeneralHash &Hash, const T *I, const T *E) { | ||
Hash.addAligned( | ||
reinterpret_cast<const uint32_t *>(I), | ||
reinterpret_cast<const uint32_t *>(E)); | ||
} | ||
}; | ||
|
||
// Add a range of bits from I to E. | ||
template<typename T> | ||
void addBits(const T *I, const T *E) { | ||
addBitsImpl<T, AlignOf<T>::Alignment_GreaterEqual_4Bytes>::add(*this, I, E); | ||
} | ||
|
||
// Add a range of uint32s | ||
void addAligned(const uint32_t *I, const uint32_t *E) { | ||
while (I < E) { | ||
mix(*I++); | ||
} | ||
} | ||
|
||
// Add a possibly unaligned sequence of bytes. | ||
void addUnaligned(const uint8_t *I, const uint8_t *E); | ||
}; | ||
|
||
} // end namespace llvm | ||
|
||
#endif |
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
//===-- llvm/ADT/Hashing.cpp - Utilities for hashing ------------*- C++ -*-===// | ||
// | ||
// The LLVM Compiler Infrastructure | ||
// | ||
// This file is distributed under the University of Illinois Open Source | ||
// License. See LICENSE.TXT for details. | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#include "llvm/ADT/Hashing.h" | ||
|
||
namespace llvm { | ||
|
||
// Add a possibly unaligned sequence of bytes. | ||
void GeneralHash::addUnaligned(const uint8_t *I, const uint8_t *E) { | ||
ptrdiff_t Length = E - I; | ||
if (uintptr_t(I) & 3 == 0) { | ||
while (Length > 3) { | ||
mix(*reinterpret_cast<const uint32_t *>(I)); | ||
I += 4; | ||
Length -= 4; | ||
} | ||
} else { | ||
while (Length > 3) { | ||
mix( | ||
uint32_t(I[0]) + | ||
(uint32_t(I[1]) << 8) + | ||
(uint32_t(I[2]) << 16) + | ||
(uint32_t(I[3]) << 24)); | ||
I += 4; | ||
Length -= 4; | ||
} | ||
} | ||
|
||
if (Length & 3) { | ||
uint32_t Data = 0; | ||
switch (Length & 3) { | ||
case 3: Data |= uint32_t(I[2]) << 16; // fall through | ||
case 2: Data |= uint32_t(I[1]) << 8; // fall through | ||
case 1: Data |= uint32_t(I[0]); break; | ||
} | ||
mix(Data); | ||
} | ||
} | ||
|
||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
//===- llvm/unittest/ADT/HashingTest.cpp ----------------------------------===// | ||
// | ||
// The LLVM Compiler Infrastructure | ||
// | ||
// This file is distributed under the University of Illinois Open Source | ||
// License. See LICENSE.TXT for details. | ||
// | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// Hashing.h unit tests. | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#include "gtest/gtest.h" | ||
#include "llvm/ADT/Hashing.h" | ||
|
||
using namespace llvm; | ||
|
||
namespace { | ||
|
||
TEST(HashingTest, EmptyHashTest) { | ||
GeneralHash Hash; | ||
ASSERT_EQ(0u, Hash.finish()); | ||
} | ||
|
||
TEST(HashingTest, IntegerHashTest) { | ||
ASSERT_TRUE(GeneralHash().add(1).finish() == GeneralHash().add(1).finish()); | ||
ASSERT_TRUE(GeneralHash().add(1).finish() != GeneralHash().add(2).finish()); | ||
} | ||
|
||
TEST(HashingTest, StringHashTest) { | ||
ASSERT_TRUE( | ||
GeneralHash().add("abc").finish() == GeneralHash().add("abc").finish()); | ||
ASSERT_TRUE( | ||
GeneralHash().add("abc").finish() != GeneralHash().add("abcd").finish()); | ||
} | ||
|
||
TEST(HashingTest, FloatHashTest) { | ||
ASSERT_TRUE( | ||
GeneralHash().add(1.0f).finish() == GeneralHash().add(1.0f).finish()); | ||
ASSERT_TRUE( | ||
GeneralHash().add(1.0f).finish() != GeneralHash().add(2.0f).finish()); | ||
} | ||
|
||
TEST(HashingTest, DoubleHashTest) { | ||
ASSERT_TRUE(GeneralHash().add(1.).finish() == GeneralHash().add(1.).finish()); | ||
ASSERT_TRUE(GeneralHash().add(1.).finish() != GeneralHash().add(2.).finish()); | ||
} | ||
|
||
TEST(HashingTest, IntegerArrayHashTest) { | ||
int a[] = { 1, 2 }; | ||
int b[] = { 1, 3 }; | ||
ASSERT_TRUE(GeneralHash().add(a).finish() == GeneralHash().add(a).finish()); | ||
ASSERT_TRUE(GeneralHash().add(a).finish() != GeneralHash().add(b).finish()); | ||
} | ||
|
||
} |
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