Commit 95cd8ee7 authored by Mark OLESEN's avatar Mark OLESEN Committed by Andrew Heather
Browse files

ENH: improve hashing overloads of string-types and HashTable/HashSet

- additional dummy template parameter to assist with supporting
  derived classes. Currently just used for string types, but can be
  extended.

- provide hash specialization for various integer types.
  Removes the need for any forwarding.

- change default hasher for HashSet/HashTable from 'string::hash'
  to `Hash<Key>`. This avoids questionable hashing calls and/or
  avoids compiler resolution problems.

  For example,
  HashSet<label>::hasher and labelHashSet::hasher now both properly
  map to Hash<label> whereas previously HashSet<label> would have
  persistently mapped to string::hash, which was incorrect.

- standardize internal hashing functors.

  Functor name is 'hasher', as per STL set/map and the OpenFOAM
  HashSet/HashTable definitions.

  Older code had a local templated name, which added unnecessary
  clutter and the template parameter was always defaulted.
  For example,

      Old:  `FixedList<label, 3>::Hash<>()`
      New:  `FixedList<label, 3>::hasher()`
      Unchanged:  `labelHashSet::hasher()`

  Existing `Hash<>` functor namings are still supported,
  but deprecated.

- define hasher and Hash specialization for bitSet and PackedList

- add symmetric hasher for 'face'.
  Starts with lowest vertex value and walks in the direction
  of the next lowest value. This ensures that the hash code is
  independent of face orientation and face rotation.

NB:
  - some of keys for multiphase handling (eg, phasePairKey)
    still use yet another function naming: `hash` and `symmHash`.
    This will be targeted for alignment in the future.
parent b060378d
......@@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2013-2017 OpenFOAM Foundation
Copyright (C) 2019 OpenCFD Ltd.
Copyright (C) 2019-2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
......@@ -59,24 +59,23 @@ class multiphaseMixtureThermo
{
public:
//- Symmetric pair of interface names
class interfacePair
:
public Pair<word>
{
public:
struct hash
{
label operator()(const interfacePair& key) const
{
return word::hash()(key.first()) + word::hash()(key.second());
}
};
// Always use symmetric hashing
using hasher = Pair<word>::symmHasher;
// Always use symmetric hashing (alias)
using hash = Pair<word>::symmHasher;
// Constructors
interfacePair() {} // = default
interfacePair() = default;
interfacePair(const word& alpha1Name, const word& alpha2Name)
:
......@@ -97,11 +96,7 @@ public:
const interfacePair& b
)
{
return
(
((a.first() == b.first()) && (a.second() == b.second()))
|| ((a.first() == b.second()) && (a.second() == b.first()))
);
return (0 != Pair<word>::compare(a, b));
}
friend bool operator!=
......@@ -117,7 +112,7 @@ public:
private:
// Private data
// Private Data
//- Dictionary of phases
PtrDictionary<phaseModel> phases_;
......@@ -140,7 +135,7 @@ private:
const dimensionedScalar deltaN_;
// Private member functions
// Private Member Functions
void calcAlphas();
......
......@@ -6,6 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
......@@ -67,24 +68,23 @@ class multiphaseMixture
{
public:
//- Symmetric pair of interface names
class interfacePair
:
public Pair<word>
{
public:
struct hash
{
label operator()(const interfacePair& key) const
{
return word::hash()(key.first()) + word::hash()(key.second());
}
};
// Always use symmetric hashing
using hasher = Pair<word>::symmHasher;
// Always use symmetric hashing (alias)
using hash = Pair<word>::symmHasher;
// Constructors
interfacePair() {} // = default
interfacePair() = default;
interfacePair(const word& alpha1Name, const word& alpha2Name)
:
......@@ -105,11 +105,7 @@ public:
const interfacePair& b
)
{
return
(
((a.first() == b.first()) && (a.second() == b.second()))
|| ((a.first() == b.second()) && (a.second() == b.first()))
);
return (0 != Pair<word>::compare(a, b));
}
friend bool operator!=
......
......@@ -186,14 +186,14 @@ int main(int argc, char *argv[])
FixedList<label, 4> list1{2, 3, 4, 5};
Info<< "list1:" << list1
<< " hash:" << FixedList<label, 4>::Hash<>()(list1) << nl
<< " hash:" << FixedList<label, 4>::hasher()(list1) << nl
<< " hash:" << Hash<FixedList<label, 4>>()(list1) << nl;
label a[4] = {0, 1, 2, 3};
FixedList<label, 4> list2(a);
Info<< "list2:" << list2
<< " hash:" << FixedList<label, 4>::Hash<>()(list2) << nl
<< " hash:" << FixedList<label, 4>::hasher()(list2) << nl
<< " hash:" << Hash<FixedList<label, 4>>()(list2) << nl;
......
......@@ -127,13 +127,13 @@ int main()
myTable.insert("sqrt2", autoPtr<double>::New(1.414214));
myTable.insert("euler", autoPtr<double>::New(0.577216));
HashTable<std::unique_ptr<double>, word, string::hash> myTable1;
HashTable<std::unique_ptr<double>> myTable1;
myTable1.set("abc", std::unique_ptr<double>(new double(42.1)));
myTable1.set("pi", std::unique_ptr<double>(new double(3.14159)));
myTable1.set("natlog", std::unique_ptr<double>(new double(2.718282)));
HashTable<autoPtr<double>, word, string::hash> myTable2;
HashTable<autoPtr<double>> myTable2;
myTable2.set("abc", autoPtr<double>(new double(42.1)));
myTable2.set("pi", autoPtr<double>(new double(3.14159)));
......@@ -148,7 +148,7 @@ int main()
{
auto iter2 = myTable2.find("pi");
Info<< nl "Got pi=";
Info<< nl << "Got pi=";
if (iter2.good())
{
Info<< **iter2 << nl;
......
......@@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011 OpenFOAM Foundation
Copyright (C) 2018 OpenCFD Ltd.
Copyright (C) 2018-2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
......@@ -80,6 +80,11 @@ void printMinMax(const HashSet<Key, Hash>& set)
int main(int argc, char *argv[])
{
Info<< "labelHashSet hasher: "
<< typeid(labelHashSet::hasher).name() << nl
<< "HashSet<label> hasher: "
<< typeid(HashSet<label>::hasher).name() << nl << nl;
hashedWordList words
{
"abc",
......
Test-Hashing.C
EXE = $(FOAM_USER_APPBIN)/Test-Hashing
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
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 3 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, see <http://www.gnu.org/licenses/>.
Class
Foam::HashFunction
Description
Hash function class.
Verify that template overloads are properly resolved
Note
The second template parameter (bool) is used for SFINAE overloading,
\*---------------------------------------------------------------------------*/
#ifndef HashFunction_H
#define HashFunction_H
#include "Hash.H"
#ifdef FULLDEBUG
#define HashTypeInfo(Args) void info() { std::cerr<< "" Args << "\n"; }
#else
#define HashTypeInfo(Args) void info() {}
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class Hash Declaration
\*---------------------------------------------------------------------------*/
template<class T, class SFINAEType=bool>
struct HashFun
{
#ifdef FULLDEBUG
static constexpr const char* name() noexcept { return "default"; }
#endif
HashTypeInfo("plain hash")
unsigned operator()(const T& obj, unsigned seed=0) const
{
return Foam::Hasher(&obj, sizeof(obj), seed);
}
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
//- Hashing for label
template<> struct HashFun<Foam::label> : Hash<label>
{
#ifdef FULLDEBUG
static constexpr const char* name() noexcept { return "label"; }
#endif
HashTypeInfo("hash label")
};
//- Hashing for pointers, interpret pointer as a integer type
template<> struct HashFun<void*> : Hash<void *>
{
#ifdef FULLDEBUG
static constexpr const char* name() noexcept { return "pointer"; }
#endif
HashTypeInfo("hash ptr")
};
//- Hashing for string types
template<class StringType>
struct HashFun
<
StringType,
typename std::enable_if
<
std::is_base_of<std::string, StringType>::value, bool
>::type
>
{
#ifdef FULLDEBUG
static constexpr const char* name() noexcept { return "string"; }
#endif
HashTypeInfo("hash string")
unsigned operator()(const std::string& obj, unsigned seed=0) const
{
return Foam::Hasher(obj.data(), obj.size(), seed);
}
};
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Various
#include "edge.H"
#include "face.H"
#include "triFace.H"
#include "Pair.H"
#include "Tuple2.H"
#include "DynamicList.H"
#include "FixedList.H"
namespace Foam
{
template<> struct HashFun<edge> : Hash<edge>
{
#ifdef FULLDEBUG
static constexpr const char* name() noexcept { return "edge"; }
#endif
HashTypeInfo("hash edge")
};
template<> struct HashFun<face> : Hash<face>
{
#ifdef FULLDEBUG
static constexpr const char* name() noexcept { return "face"; }
#endif
HashTypeInfo("hash face")
};
template<> struct HashFun<triFace> : Hash<triFace>
{
#ifdef FULLDEBUG
static constexpr const char* name() noexcept { return "triFace"; }
#endif
HashTypeInfo("hash triFace")
};
template<class T>
struct HashFun<Pair<T>> : Hash<Pair<T>>
{
#ifdef FULLDEBUG
static constexpr const char* name() noexcept { return "Pair"; }
#endif
HashTypeInfo("hash Pair")
};
template<class T1, class T2>
struct HashFun<Tuple2<T1, T2>> : Hash<Tuple2<T1, T2>>
{
#ifdef FULLDEBUG
static constexpr const char* name() noexcept { return "Tuple2"; }
#endif
HashTypeInfo("hash Tuple2")
};
template<class T>
struct HashFun<List<T>> : Hash<List<T>>
{
#ifdef FULLDEBUG
static constexpr const char* name() noexcept { return "List"; }
#endif
HashTypeInfo("hash List")
};
template<class T> struct HashFun<UList<T>> : Hash<UList<T>>
{
#ifdef FULLDEBUG
static constexpr const char* name() noexcept { return "UList"; }
#endif
HashTypeInfo("hash UList")
};
template<class T, int SizeMin>
struct HashFun<DynamicList<T, SizeMin>> : Hash<DynamicList<T, SizeMin>>
{
#ifdef FULLDEBUG
static constexpr const char* name() noexcept { return "DynamicList"; }
#endif
HashTypeInfo("hash DynamicList")
};
template<class T, unsigned N>
struct HashFun<FixedList<T, N>> : Hash<FixedList<T, N>>
{
#ifdef FULLDEBUG
static constexpr const char* name() noexcept { return "FixedList"; }
#endif
HashTypeInfo("hash FixedList")
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //
Test-Hashing1.C
EXE = $(FOAM_USER_APPBIN)/Test-Hashing1
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
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 3 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, see <http://www.gnu.org/licenses/>.
Application
Test-Hashing1
Description
Test/verify overloads of Hash function
\*---------------------------------------------------------------------------*/
#include "IOstreams.H"
#include "IOobject.H"
#include "IFstream.H"
#include "stringList.H"
#include "labelList.H"
#include "labelPair.H"
#include "wordPair.H"
#include "edgeList.H"
#include "faceList.H"
#include "triFaceList.H"
#define FULLDEBUG
#include "HashFunction.H"
using namespace Foam;
template<class T>
unsigned rawHasher(const T& obj)
{
return Foam::Hasher(&obj, sizeof(T), 0u);
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Main program:
int main(int argc, char *argv[])
{
{
typedef unsigned Type;
Type value = 100;
Info<< "hash " << typeid(value).name() << " of " << value << nl;
Info<< " Hasher: " << rawHasher(value) << nl;
Info<< " Hash<>: " << Hash<Type>()(value) << nl;
}
{
typedef int32_t Type;
Type value = 100;
Info<< "hash " << typeid(value).name() << " of " << value << nl;
Info<< " Hasher: " << rawHasher(value) << nl;
Info<< " Hash<>: " << Hash<Type>()(value) << nl;
}
{
typedef int64_t Type;
Type value = 100;
Info<< "hash " << typeid(value).name() << " of " << value << nl;
Info<< " Hasher: " << rawHasher(value) << nl;
Info<< " Hash<>: " << Hash<Type>()(value) << nl;
}
HashFun<std::string>().info();
HashFun<string>().info();
HashFun<Foam::word>().info();
HashFun<Foam::keyType>().info();
HashFun<int>().info();
HashFun<label>().info();
HashFun<float>().info();
HashFun<double>().info();
{
float value = 15.f;
Info<< "hash of " << Foam::name(&value)
<< " = " << HashFun<void*>()(&value) << nl;
}
HashFun<labelList>().info();
HashFun<wordUList>().info();
HashFun<edge>().info();
HashFun<Pair<label>>().info();
HashFun<labelPair>().info();
HashFun<labelPairPair>().info();
HashFun<Tuple2<label, word>>().info();
{
typedef Tuple2<label, word> Type;
Type obj(10, "test");
Info<< obj << " hash=" << Hash<Type>()(obj) << nl;
}
{
typedef Tuple2<label, label> Type;
Type obj(10, 12);
Info<< obj << " hash=" << Hash<Type>()(obj) << nl;
}
{
typedef Pair<label> Type;
Type obj(10, 12);
Info<< obj << " hash=" << Hash<Type>()(obj) << nl;
}
{
typedef std::pair<label, label> Type;
Type obj(10, 12);
Info<< obj << " hash=" << Hash<Type>()(obj) << nl;
HashSet<Type> hs;
hs.insert(obj);
hs.erase(obj);
}
{
Pair<label>::hasher op;
Info<< "hasher: " << op(Pair<label>(10, 12)) << nl;
}
// Not supported
#if 0
{
Tuple2<label, label>::hasher op;
Info<< "hasher: " << op(Tuple2<label>(10, 12)) << nl;
}
#endif
Info<< "\nEnd\n" << nl;
return 0;
}
// ************************************************************************* //
Test-Hashing2.C
EXE = $(FOAM_USER_APPBIN)/Test-Hashing2
EXE_INC = ${c++LESSWARN}
/* EXE_LIBS = */
......@@ -6,7 +6,7 @@
\\/ M anipulation |
-----------------------------------------------------------------