Commit 44a86232 authored by Mark Olesen's avatar Mark Olesen
Browse files

Added Jenkin's hash functions in C++ form

- not much speed difference between SuperFastHash and Jenkin's lookup3 but
  both are 5-10% faster than what is currently implemented in Foam::string,
  albeit inlining probably helps there.

- TODO: integration with existing infrastructure
parent f83e4cbd
testHashing.C
EXE = $(FOAM_USER_APPBIN)/testHashing
/*-------------------------------*- C++ -*---------------------------------*\
| ========= |
| \\ / OpenFOAM |
| \\ / |
| \\ / The Open Source CFD Toolbox |
| \\/ http://www.OpenFOAM.org |
\*-------------------------------------------------------------------------*/
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
stringList
(
"The quick brown fox jumps over the lazy dog"
"The best hash is the one you don't write yourself!"
)
labelList
(
0
1
100
1000
-1
-10
-100
)
labelListList
(
(0)
(0 0)
(0 0 0)
(0 1)
(100 1000)
(0 1 100 1000)
)
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 1991-2009 OpenCFD Ltd.
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Application
testHashing
Description
\*---------------------------------------------------------------------------*/
#include "IOstreams.H"
#include "IOobject.H"
#include "IFstream.H"
#include "stringList.H"
#include "labelList.H"
#include "labelPair.H"
#include "Hashing.H"
using namespace Foam;
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Main program:
int main(int argc, char *argv[])
{
IFstream is("hashingTests");
while (is.good())
{
const word listType(is);
Info<< endl;
IOobject::writeDivider(Info);
Info<< listType << endl;
if (listType == "stringList")
{
Info<< "contiguous = " << contiguous<string>() << endl << endl;
stringList lst(is);
forAll(lst, i)
{
unsigned hash1 = Hashing::jenkins(lst[i]);
unsigned hash2 = string::hash()(lst[i]);
Info<< hex << hash1
<< " (prev " << hash2 << ")"
<< ": " << lst[i] << endl;
}
}
else if (listType == "labelList")
{
Info<<"contiguous = " << contiguous<label>() << " "
<< "sizeof(label) " << unsigned(sizeof(label)) << endl << endl;
labelList lst(is);
unsigned hash4 = 0;
forAll(lst, i)
{
unsigned hash1 = Hashing::intHash(lst[i]);
unsigned hash2 = Hashing::jenkins
(
reinterpret_cast<const char*>(&lst[i]),
sizeof(label)
);
unsigned hash3 = Hashing::jenkins
(
reinterpret_cast<const unsigned*>(&lst[i]),
1
);
// incremental
hash4 = Hashing::jenkins
(
reinterpret_cast<const char*>(&lst[i]),
sizeof(label),
hash4
);
Info<< hex << hash1
<< " (alt: " << hash2 << ")"
<< " (alt: " << hash3 << ")"
<< " (incr: " << hash4 << ")"
<< ": " << dec << lst[i] << endl;
}
if (contiguous<label>())
{
unsigned hash1 = Hashing::jenkins
(
lst.cdata(),
lst.size() * sizeof(label)
);
Info<<"contiguous hashed value " << hex << hash1 << endl;
}
}
else if (listType == "labelListList")
{
List< List<label> > lst(is);
forAll(lst, i)
{
unsigned hash1 = Hashing::jenkins
(
reinterpret_cast<const char*>(lst[i].cdata()),
lst[i].size() * sizeof(label)
);
Info<< hex << hash1
<< ": " << dec << lst[i] << endl;
}
}
}
return 0;
}
// ************************************************************************* //
testHashingSpeed.C
EXE = $(FOAM_USER_APPBIN)/testHashingSpeed
This diff is collapsed.
......@@ -52,6 +52,8 @@ $(strings)/fileName/fileNameIO.C
$(strings)/keyType/keyTypeIO.C
$(strings)/wordRe/wordReIO.C
primitives/hashes/Hashing/Hashing.C
sha1 = primitives/hashes/SHA1
$(sha1)/SHA1.C
$(sha1)/SHA1Digest.C
......
This diff is collapsed.
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 1991-2009 OpenCFD Ltd.
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Namespace
Foam::Hashing
Description
Misc. hashing functions, mostly from Bob Jenkins.
The Jenkins hashing function(s) is similar in speed to Paul Hsieh's
SuperFast hash, but is public domain, supports incremental hashing
and has been reported to have better characteristics.
It is also what postgresql seems to be using.
SeeAlso
http://burtleburtle.net/bob/c/lookup3.c
SourceFiles
Hashing.C
\*---------------------------------------------------------------------------*/
#ifndef Hashing_H
#define Hashing_H
#include <string>
#include <climits>
#include <cstddef>
#include <stdint.h> // C++0x uses <cstdint>
#include "label.H"
#include "uLabel.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Macro defines
/**
* @def bitRotateLeft(val, nBits)
* Left-rotate a 32-bit value and carry by nBits
*/
#define bitRotateLeft(x, nBits) (((x) << (nBits)) | ((x) >> (32 - (nBits))))
/**
* @def bitMixer(a, b, c)
* Mix three 32-bit values reversibly.
*/
#define bitMixer(a, b, c) \
{ \
a -= c; a ^= bitRotateLeft(c, 4); c += b; \
b -= a; b ^= bitRotateLeft(a, 6); a += c; \
c -= b; c ^= bitRotateLeft(b, 8); b += a; \
a -= c; a ^= bitRotateLeft(c,16); c += b; \
b -= a; b ^= bitRotateLeft(a,19); a += c; \
c -= b; c ^= bitRotateLeft(b, 4); b += a; \
}
/**
* @def bitMixerFinal(a, b, c)
* Final mixing of three 32-bit values (a,b,c) into c
*/
#define bitMixerFinal(a, b, c) \
{ \
c ^= b; c -= bitRotateLeft(b, 14); \
a ^= c; a -= bitRotateLeft(c, 11); \
b ^= a; b -= bitRotateLeft(a, 25); \
c ^= b; c -= bitRotateLeft(b, 16); \
a ^= c; a -= bitRotateLeft(c, 4); \
b ^= a; b -= bitRotateLeft(a, 14); \
c ^= b; c -= bitRotateLeft(b, 24); \
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace Hashing
{
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
//- Bob Jenkins's 96-bit mixer hashing function (lookup3)
// @param[in] data - an array of uint32_t values
// @param[in] len - the number of values (not bytes)
// @param[in] seed - the previous hash, or an arbitrary value
uint32_t jenkins(const uint32_t*, size_t length, uint32_t seed = 0);
//- Bob Jenkins's 96-bit mixer hashing function returning twin hash values
// @param[in] data - an array of uint32_t values
// @param[in] len - the number of values (not bytes)
// @param[in] hash1 - the previous hash, or an arbitrary value
// on output, the primary hash value
// @param[in] hash1 - the previous hash, or an arbitrary value
// on output, the secondary hash value
uint32_t jenkinsTwin
(
const uint32_t*,
size_t len,
uint32_t& hash1,
uint32_t& hash2
);
//- Bob Jenkins's 96-bit mixer hashing function (lookup3)
// @param[in] data - a character stream
// @param[in] len - the number of bytes
// @param[in] seed - the previous hash, or an arbitrary value
uint32_t jenkins(const void* data, size_t len, uint32_t seed = 0);
//- Hashing a C++ string with Jenkins' 96-bit mixer
inline uint32_t jenkins(const std::string& str, uint32_t seed = 0)
{
return jenkins(str.data(), str.size(), seed);
}
//- Hash an unsigned long like two 32bit values
inline uint32_t jenkins(const unsigned long& val)
{
uint32_t a = val >> 32;
uint32_t b = val & 0xFFFFFFFF;
uint32_t c = 0;
bitMixerFinal(a,b,c);
return c;
}
//- Hash a (64-bit) pointer like any long
// Treats bits as zero if the pointer is actually 32bit
inline uint32_t pointerHash(const void* const& p)
{
return jenkins(long(p));
}
#if UINT_MAX > WANTEDURANGE
//- Hash a uLabel
inline unsigned intHash(const uLabel& val1)
{
uint32_t a = val1;
uint32_t b = 0;
uint32_t c = 0;
bitMixerFinal(a,b,c);
return c;
}
//- Hash a uLabel pair
inline unsigned intHash
(
const uLabel& val1,
const uLabel& val2
)
{
uint32_t a = val1;
uint32_t b = val2;
uint32_t c = 0;
bitMixerFinal(a,b,c);
return c;
}
//- Hash a uLabel triplet
inline unsigned intHash
(
const uLabel& val1,
const uLabel& val2,
const uLabel& val3
)
{
uint32_t a = val1;
uint32_t b = val2;
uint32_t c = val3;
bitMixer(a,b,c);
bitMixerFinal(a,b,c);
return c;
}
#else
//- Hash a uLabel
inline unsigned intHash
(
const uLabel& val1
)
{
uint32_t a = val1 >> 32;
uint32_t b = val1 & 0xFFFFFFFF;
uint32_t c = 0;
bitMixerFinal(a,b,c);
return c;
}
//- Hash a uLabel pair
inline unsigned intHash
(
const uLabel& val1,
const uLabel& val2
)
{
uint32_t a = val1 >> 32;
uint32_t b = val1 & 0xFFFFFFFF;
uint32_t c = val2 >> 32;
bitMixer(a,b,c);
a += val2 & 0xFFFFFFFF;
bitMixerFinal(a,b,c);
return c;
}
//- Hash a uLabel triplet
inline unsigned intHash
(
const uLabel& val1,
const uLabel& val2,
const uLabel& val3
)
{
uint32_t a = val1 >> 32;
uint32_t b = val1 & 0xFFFFFFFF;
uint32_t c = val2 >> 32;
bitMixer(a,b,c);
a += val2 & 0xFFFFFFFF;
b += val3 >> 32;
c += val3 & 0xFFFFFFFF;
bitMixerFinal(a,b,c);
return c;
}
#endif
//- Hash a label as uLabel
inline unsigned intHash(const label& val)
{
return intHash(static_cast<uLabel>(val));
}
//- Hash a label pair
inline unsigned intHash
(
const label& val1,
const label& val2
)
{
return intHash
(
static_cast<uLabel>(val1),
static_cast<uLabel>(val2)
);
}
//- Hash a label triplet
inline unsigned intHash
(
const label& val1,
const label& val2,
const label& val3
)
{
return intHash
(
static_cast<uLabel>(val1),
static_cast<uLabel>(val2),
static_cast<uLabel>(val3)
);
}
#if 0
inline unsigned intHashCommutative(const label s1, const label s2)
{
if (s1 < s2)
{
intHash(s1, s2);
}
else
{
intHash(s2, s1);
}
}
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Hashing
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //
......@@ -114,7 +114,7 @@ public:
// Constructors
//- Construct null
inline SHA1();
inline SHA1();
//- Construct and append initial std::string
explicit inline SHA1(const std::string&);
......@@ -124,24 +124,24 @@ public:
// Member Functions
//- Reset the hashed data before appending more
void clear();
//- Reset the hashed data before appending more
void clear();
//- Append data for processing
inline SHA1& append(const char* data, size_t len);
//- Append data for processing
inline SHA1& append(const char* data, size_t len);
//- Append string for processing
//- Append string for processing
inline SHA1& append(const std::string&);
//- Append string for processing
inline SHA1& append(const char* str);
//- Append string for processing
inline SHA1& append(const char* str);
//- Finalized the calculations (normally not needed directly).
//- Finalized the calculations (normally not needed directly).
// Returns false if no bytes were passed for processing
bool finalize();
bool finalize();
//- Calculate current digest from appended data.
SHA1Digest digest() const;
SHA1Digest digest() const;
// Member Operators
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment