ENH: improve HashTable iterator access and management

- provide key_iterator/const_key_iterator for all hashes,
  reuse directly for HashSet as iterator/const_iterator, respectively.

- additional keys() method for HashTable that returns a wrapped to
  a pair of begin/end const_iterators with additional size/empty
  information that allows these to be used directly by anything else
  expecting things with begin/end/size. Unfortunately does not yet
  work with std::distance().

  Example,
     for (auto& k : labelHashTable.keys())
     {
        ...
     }
This commit is contained in:
Mark Olesen
2017-05-04 10:17:18 +02:00
parent 759306a3e2
commit 03d180724b
16 changed files with 711 additions and 312 deletions

View File

@ -69,6 +69,12 @@ int main(int argc, char *argv[])
Info<< "tableA keys: "; tableA.writeKeys(Info) << endl; Info<< "tableA keys: "; tableA.writeKeys(Info) << endl;
auto keyIterPair = tableA.keys();
for (const auto& i : keyIterPair)
{
Info<<" keys: " << i << endl;
}
Map<label> mapA Map<label> mapA
{ {
{ 1, 1 }, { 1, 1 },
@ -193,7 +199,7 @@ int main(int argc, char *argv[])
Info<< "setD : " << flatOutput(setD) << endl; Info<< "setD : " << flatOutput(setD) << endl;
// this doesn't work (yet?) // This should not work (yet?)
// setD[12] = true; // setD[12] = true;
List<label> someLst(10); List<label> someLst(10);

View File

@ -24,6 +24,7 @@ License
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
#include "HashTable.H" #include "HashTable.H"
#include "List.H"
#include "IOstreams.H" #include "IOstreams.H"
#include "IStringStream.H" #include "IStringStream.H"
#include "OStringStream.H" #include "OStringStream.H"
@ -177,12 +178,23 @@ int main()
Info<< "\ntable1" << table1 << nl; Info<< "\ntable1" << table1 << nl;
Info<< "\nrange-for(table1)" << nl; Info<< "\nrange-for(table1) - returns values" << nl;
for (auto const& it : table1) for (const auto& it : table1)
{ {
Info<< " " << it << nl; Info<< "val:" << it << nl;
} }
Info<< "\nrange-for(table1.keys()) - returns keys" << nl;
for (const auto& k : table1.keys())
{
Info<< "key:" << k << nl;
}
// These do not yet work. Issues resolving the distance.
//
// List<scalar> table1vals(table1.begin(), table1.end());
// wordList table1keys(table1.begin(), table1.end());
Info<< "\nDone\n"; Info<< "\nDone\n";
return 0; return 0;

View File

@ -0,0 +1,3 @@
Test-cpluplus1.C
EXE = $(FOAM_USER_APPBIN)/Test-cpluplus1

View File

@ -0,0 +1,2 @@
/* EXE_INC = -I$(LIB_SRC)/cfdTools/include */
/* EXE_LIBS = -lfiniteVolume */

View File

@ -0,0 +1,88 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2017 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 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/>.
Description
Test miscellaneous C++ templates/functionality.
\*---------------------------------------------------------------------------*/
#include "string.H"
#include "IOstreams.H"
#include "UList.H"
#include "HashSet.H"
#include <typeinfo>
#include <type_traits>
#include <utility>
using namespace Foam;
// Macros to stringify macro contents.
#define STRINGIFY(content) #content
#define STRING_QUOTE(input) STRINGIFY(input)
#define PRINT_TYPEID(arg) \
Info<< typeid(arg).name() << " <= typeid of " << STRING_QUOTE(arg) << nl
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Main program:
int main(int argc, char *argv[])
{
Info<< "various declaration types" << nl << nl;
PRINT_TYPEID(label);
PRINT_TYPEID(decltype(UList<label>::value_type()));
PRINT_TYPEID(decltype(std::declval<UList<label>>().cbegin()));
PRINT_TYPEID(decltype(*(std::declval<UList<label>>().cbegin())));
Info<< nl;
PRINT_TYPEID(decltype(HashTable<label>::key_type()));
PRINT_TYPEID(decltype(HashTable<label>::value_type()));
// Not yet: PRINT_TYPEID(decltype(HashTable<label>::mapped_type()));
PRINT_TYPEID(decltype(std::declval<HashTable<label>>().begin()));
PRINT_TYPEID(decltype(std::declval<const HashTable<label>>().begin()));
PRINT_TYPEID(decltype(*(std::declval<HashTable<label>>().begin())));
PRINT_TYPEID(decltype(*(std::declval<const HashTable<label>>().begin())));
PRINT_TYPEID(decltype(std::declval<const HashTable<label>>().keys()));
Info<< nl;
PRINT_TYPEID(decltype(HashSet<label>::key_type()));
PRINT_TYPEID(decltype(HashSet<label>::value_type()));
// Not yet: PRINT_TYPEID(decltype(HashSet<label>::mapped_type()));
PRINT_TYPEID(decltype(std::declval<HashSet<label>>().begin()));
PRINT_TYPEID(decltype(std::declval<const HashSet<label>>().begin()));
PRINT_TYPEID(decltype(*(std::declval<HashSet<label>>().begin())));
PRINT_TYPEID(decltype(*(std::declval<const HashSet<label>>().begin())));
Info<< nl;
Info << "\nEnd\n" << endl;
return 0;
}
// ************************************************************************* //

View File

@ -29,6 +29,9 @@ Description
#include "pTraits.H" #include "pTraits.H"
#include "vector.H" #include "vector.H"
#include "tensor.H" #include "tensor.H"
#include "uLabel.H"
#include <type_traits>
using namespace Foam; using namespace Foam;
@ -40,7 +43,10 @@ void printTraits()
{ {
Info<< pTraits<T>::typeName Info<< pTraits<T>::typeName
<< ": zero=" << pTraits<T>::zero << ": zero=" << pTraits<T>::zero
<< " one=" << pTraits<T>::one << endl; << " one=" << pTraits<T>::one
<< " integral=" << std::is_integral<T>::value
<< " floating=" << std::is_floating_point<T>::value
<< endl;
} }
@ -80,6 +86,21 @@ int main()
label def = label(); label def = label();
Info<< "intialized primitive:"<< def << endl; Info<< "intialized primitive:"<< def << endl;
Info<< nl << "some interesting label limits:" << nl;
std::cout<< "sizeof = " << sizeof(label) << nl;
std::cout<< "min = " << pTraits<label>::min << nl;
std::cout<< "max = " << pTraits<label>::max << nl;
std::cout<< "umax = " << pTraits<uLabel>::max << nl;
std::cout<< "max_2 = " << pTraits<label>::max/2 << " == "
<< (1 << (sizeof(label)*8-2)) << nl;
std::cout<< "max_4 = " << pTraits<label>::max/4 << " == "
<< (1 << (sizeof(label)*8-3)) << nl;
std::cout<< "max_8 = " << pTraits<label>::max/8 << " == "
<< (1 << (sizeof(label)*8-4)) << nl;
Info<< "End\n" << endl; Info<< "End\n" << endl;
return 0; return 0;

View File

@ -140,6 +140,7 @@ Foam::label Foam::HashSet<Key, Hash>::insert(const UList<Key>& lst)
return insertMultiple(lst.begin(), lst.end()); return insertMultiple(lst.begin(), lst.end());
} }
template<class Key, class Hash> template<class Key, class Hash>
template<unsigned Size> template<unsigned Size>
Foam::label Foam::HashSet<Key, Hash>::insert(const FixedList<Key, Size>& lst) Foam::label Foam::HashSet<Key, Hash>::insert(const FixedList<Key, Size>& lst)
@ -147,6 +148,7 @@ Foam::label Foam::HashSet<Key, Hash>::insert(const FixedList<Key, Size>& lst)
return insertMultiple(lst.begin(), lst.end()); return insertMultiple(lst.begin(), lst.end());
} }
template<class Key, class Hash> template<class Key, class Hash>
Foam::label Foam::HashSet<Key, Hash>::insert(std::initializer_list<Key> lst) Foam::label Foam::HashSet<Key, Hash>::insert(std::initializer_list<Key> lst)
{ {
@ -209,7 +211,7 @@ bool Foam::HashSet<Key, Hash>::operator==(const HashSet<Key, Hash>& rhs) const
template<class Key, class Hash> template<class Key, class Hash>
bool Foam::HashSet<Key, Hash>::operator!=(const HashSet<Key, Hash>& rhs) const bool Foam::HashSet<Key, Hash>::operator!=(const HashSet<Key, Hash>& rhs) const
{ {
return !(operator==(rhs)); return !operator==(rhs);
} }
@ -319,51 +321,63 @@ Foam::operator^
return out; return out;
} }
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
template<class Key, class Hash> template<class Key, class Hash>
inline typename Foam::HashSet<Key, Hash>::iterator inline typename Foam::HashSet<Key, Hash>::iterator
Foam::HashSet<Key, Hash>::begin() Foam::HashSet<Key, Hash>::begin()
{ {
return iterator(this->ParentClass::begin()); return HashTableCore::iterator_begin<iterator>
(
static_cast<parent_type&>(*this)
);
} }
template<class Key, class Hash> template<class Key, class Hash>
inline typename Foam::HashSet<Key, Hash>::const_iterator inline typename Foam::HashSet<Key, Hash>::const_iterator
Foam::HashSet<Key, Hash>::begin() const Foam::HashSet<Key, Hash>::begin() const
{ {
return const_iterator(this->ParentClass::cbegin()); return HashTableCore::iterator_begin<const_iterator>
(
static_cast<const parent_type&>(*this)
);
} }
template<class Key, class Hash> template<class Key, class Hash>
inline typename Foam::HashSet<Key, Hash>::const_iterator inline typename Foam::HashSet<Key, Hash>::const_iterator
Foam::HashSet<Key, Hash>::cbegin() const Foam::HashSet<Key, Hash>::cbegin() const
{ {
return this->begin(); return HashTableCore::iterator_begin<const_iterator>
(
static_cast<const parent_type&>(*this)
);
} }
template<class Key, class Hash> template<class Key, class Hash>
inline const typename Foam::HashSet<Key, Hash>::iterator& inline const typename Foam::HashSet<Key, Hash>::iterator&
Foam::HashSet<Key, Hash>::end() Foam::HashSet<Key, Hash>::end()
{ {
using iter_type = typename HashSet<Key, Hash>::iterator; return HashTableCore::iterator_end<iterator>();
return HashTableCore::endIteratorRef<iter_type>();
} }
template<class Key, class Hash> template<class Key, class Hash>
inline const typename Foam::HashSet<Key, Hash>::const_iterator& inline const typename Foam::HashSet<Key, Hash>::const_iterator&
Foam::HashSet<Key, Hash>::end() const Foam::HashSet<Key, Hash>::end() const
{ {
using iter_type = typename HashSet<Key, Hash>::const_iterator; return HashTableCore::iterator_end<const_iterator>();
return HashTableCore::endIteratorRef<iter_type>();
} }
template<class Key, class Hash> template<class Key, class Hash>
inline const typename Foam::HashSet<Key, Hash>::const_iterator& inline const typename Foam::HashSet<Key, Hash>::const_iterator&
Foam::HashSet<Key, Hash>::cend() const Foam::HashSet<Key, Hash>::cend() const
{ {
using iter_type = typename HashSet<Key, Hash>::const_iterator; return HashTableCore::iterator_cend<const_iterator>();
return HashTableCore::endIteratorRef<iter_type>();
} }

View File

@ -68,8 +68,6 @@ class HashSet
: :
public HashTable<nil, Key, Hash> public HashTable<nil, Key, Hash>
{ {
typedef HashTable<nil, Key, Hash> ParentClass;
// Private Member Functions // Private Member Functions
//- Insert values, using begin/end iterators. //- Insert values, using begin/end iterators.
@ -92,18 +90,31 @@ class HashSet
public: public:
//- The template instance used for this HashSet
typedef HashSet<Key, Hash> this_type;
//- The template instance used for the parent HashTable
typedef HashTable<nil, Key, Hash> parent_type;
//- An iterator, returning reference to the key
using iterator = typename parent_type::key_iterator;
//- A const_iterator, returning reference to the key
using const_iterator = typename parent_type::const_key_iterator;
// Constructors // Constructors
//- Construct given initial size //- Construct given initial size
HashSet(const label size = 128) HashSet(const label size = 128)
: :
ParentClass(size) parent_type(size)
{} {}
//- Construct from Istream //- Construct from Istream
HashSet(Istream& is) HashSet(Istream& is)
: :
ParentClass(is) parent_type(is)
{} {}
//- Construct from UList of Key //- Construct from UList of Key
@ -119,19 +130,19 @@ public:
//- Construct as copy //- Construct as copy
HashSet(const HashSet<Key, Hash>& hs) HashSet(const HashSet<Key, Hash>& hs)
: :
ParentClass(hs) parent_type(hs)
{} {}
//- Construct by transferring the parameter contents //- Construct by transferring the parameter contents
HashSet(const Xfer<HashSet<Key, Hash>>& hs) HashSet(const Xfer<HashSet<Key, Hash>>& hs)
: :
ParentClass(hs) parent_type(hs)
{} {}
//- Construct by transferring the parameter contents //- Construct by transferring the parameter contents
HashSet(const Xfer<HashTable<nil, Key, Hash>>& hs) HashSet(const Xfer<HashTable<nil, Key, Hash>>& hs)
: :
HashTable<nil, Key, Hash>(hs) parent_type(hs)
{} {}
//- Construct from the keys of another HashTable, //- Construct from the keys of another HashTable,
@ -147,7 +158,7 @@ public:
//- Insert a new entry //- Insert a new entry
bool insert(const Key& key) bool insert(const Key& key)
{ {
return this->ParentClass::insert(key, nil()); return this->parent_type::insert(key, nil());
} }
//- Insert keys from the list of Key //- Insert keys from the list of Key
@ -191,77 +202,38 @@ public:
//- Unset the specified key - same as erase //- Unset the specified key - same as erase
bool unset(const Key& key) bool unset(const Key& key)
{ {
return this->ParentClass::erase(key); return this->parent_type::erase(key);
} }
//- Unset the listed keys - same as erase //- Unset the listed keys - same as erase
label unset(const UList<Key>& lst) label unset(const UList<Key>& lst)
{ {
return this->ParentClass::erase(lst); return this->parent_type::erase(lst);
} }
//- Unset the listed keys - same as erase //- Unset the listed keys - same as erase
template<unsigned Size> template<unsigned Size>
label unset(const FixedList<Key, Size>& lst) label unset(const FixedList<Key, Size>& lst)
{ {
return this->ParentClass::erase(lst); return this->parent_type::erase(lst);
} }
//- Unset the listed keys - same as erase //- Unset the listed keys - same as erase
label unset(std::initializer_list<Key> lst) label unset(std::initializer_list<Key> lst)
{ {
return this->ParentClass::erase(lst); return this->parent_type::erase(lst);
} }
// STL iterator // STL iterators
//- An STL-conforming iterator iterator begin();
struct iterator const_iterator begin() const;
: const_iterator cbegin() const;
public ParentClass::iterator
{
using parent = typename ParentClass::iterator;
//- Implicit conversion const iterator& end();
iterator(const parent& iter) const const_iterator& end() const;
: const const_iterator& cend() const;
parent(iter)
{}
//- Return the key
auto operator*() const -> const Key&
{
return this->key();
}
};
//- An STL-conforming const_iterator
struct const_iterator
:
public ParentClass::const_iterator
{
using parent = typename ParentClass::const_iterator;
//- Implicit conversion
const_iterator(const parent& iter)
:
parent(iter)
{}
//- Return the key
auto operator*() const -> const Key&
{
return this->key();
}
};
auto begin() -> iterator;
auto begin() const -> const_iterator;
auto cbegin() const -> const_iterator;
auto end() -> const iterator&;
auto end() const -> const const_iterator&;
auto cend() const -> const const_iterator&;
// Writing // Writing
@ -276,15 +248,18 @@ public:
// Member Operators // Member Operators
//- This operation doesn't make much sense for a hash-set
void operator()(const Key& key) = delete;
//- Return true if the entry exists, same as found() //- Return true if the entry exists, same as found()
inline bool operator[](const Key& key) const; inline bool operator[](const Key& key) const;
//- Equality. Two hashset are equal when they have the same keys. //- Equality. Two hashset are equal when they have the same keys.
// Independent of table size or order. // Independent of table size or order.
bool operator==(const HashSet<Key, Hash>& rhs) const; bool operator==(const this_type& rhs) const;
//- The opposite of the equality operation. //- The opposite of the equality operation.
bool operator!=(const HashSet<Key, Hash>& rhs) const; bool operator!=(const this_type& rhs) const;
//- Assignment from a UList of keys //- Assignment from a UList of keys

View File

@ -3,7 +3,7 @@
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | \\ / O peration |
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation \\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation
\\/ M anipulation | \\/ M anipulation | Copyright (C) 2017 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -336,7 +336,7 @@ bool Foam::HashTable<T, Key, Hash>::set
template<class T, class Key, class Hash> template<class T, class Key, class Hash>
bool Foam::HashTable<T, Key, Hash>::iteratorBase::erase() bool Foam::HashTable<T, Key, Hash>::iterator_base::erase()
{ {
// Note: entryPtr_ is nullptr for end(), so this catches that too // Note: entryPtr_ is nullptr for end(), so this catches that too
if (entryPtr_) if (entryPtr_)
@ -515,7 +515,7 @@ void Foam::HashTable<T, Key, Hash>::resize(const label sz)
for (const_iterator iter = cbegin(); iter != cend(); ++iter) for (const_iterator iter = cbegin(); iter != cend(); ++iter)
{ {
tmpTable->insert(iter.key(), *iter); tmpTable->insert(iter.key(), iter.object());
} }
const label oldSize = tableSize_; const label oldSize = tableSize_;
@ -645,7 +645,7 @@ void Foam::HashTable<T, Key, Hash>::operator=
clear(); clear();
} }
for (const Tuple2<Key, T>& pair : lst) for (const auto& pair : lst)
{ {
insert(pair.first(), pair.second()); insert(pair.first(), pair.second());
} }
@ -684,7 +684,7 @@ bool Foam::HashTable<T, Key, Hash>::operator!=
const HashTable<T, Key, Hash>& rhs const HashTable<T, Key, Hash>& rhs
) const ) const
{ {
return !(operator==(rhs)); return !operator==(rhs);
} }

View File

@ -34,6 +34,13 @@ Note
often result in a different hash order. Use a sorted table-of-contents often result in a different hash order. Use a sorted table-of-contents
when the hash order is important. when the hash order is important.
The end iterator of all hash-tables has a nullptr to the hash entry.
Thus avoid separate allocation for each table and use a single one with
a nullptr. The hash-table iterators always have an entry-pointer as the
first member data, which allows reinterpret_cast from anything else with
a nullptr as its first data member.
The nullObject is such an item (with a nullptr data member).
SourceFiles SourceFiles
HashTableI.H HashTableI.H
HashTable.C HashTable.C
@ -78,25 +85,15 @@ Ostream& operator<<(Ostream& os, const HashTable<T, Key, Hash>& tbl);
Class HashTableCore Declaration Class HashTableCore Declaration
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
//- Template-invariant bits for HashTable. //- Bits that are independent of the HashTable template parameters.
// This also includes a global end-iterator. struct HashTableCore
//
// The end iterator of all hash-tables has a nullptr to the hash entry.
// Thus avoid separate allocation for each table and use a single one with
// a nullptr.
// The hash-table iterators always have this as its first member data,
// so we can reinterpret_cast from anything else that has a nullptr for its
// first data member. This is now also the case for the NullObject.
class HashTableCore
{ {
public: //- Maximum allowable internal table size. Approximately labelMax/4
//- Return a canonical (power-of-two) size
static label canonicalSize(const label size);
//- Maximum allowable table size
static const label maxTableSize; static const label maxTableSize;
//- Return a canonical (power-of-two) of the requested size.
static label canonicalSize(const label requested_size);
//- Construct null //- Construct null
HashTableCore() HashTableCore()
{} {}
@ -104,21 +101,57 @@ public:
//- Define template name and debug //- Define template name and debug
ClassName("HashTable"); ClassName("HashTable");
protected:
static_assert static_assert
( (
sizeof(NullObject) >= sizeof(void*), sizeof(NullObject) >= sizeof(void*),
"NullObject is too small to reinterpret_cast as HashTable::iterator" "NullObject is too small to reinterpret_cast as HashTable::iterator"
); );
//- Reinterpret a NullObject as a hash-table iterator.
template<class Iterator> //- Factory method to create a non-const iterator begin
inline static const Iterator& endIteratorRef() template<class IteratorType, class TableType>
inline static IteratorType iterator_begin(TableType& table);
//- Factory method to create a const iterator begin
template<class IteratorType, class TableType>
inline static IteratorType iterator_begin(const TableType& table);
//- Factory method to create a const iterator begin
template<class IteratorType, class TableType>
inline static IteratorType iterator_cbegin(const TableType& table);
//- Factory method to create a non-const iterator end
// Simply reinterprets a NullObject as a hash-table iterator.
template<class IteratorType>
inline static const IteratorType& iterator_end();
//- Factory method to create a const iterator cend
// Simply reinterprets a NullObject as a hash-table iterator.
template<class IteratorType>
inline static const IteratorType& iterator_cend();
//- Factory class for creating a begin/end pair for any const iterator.
template<class IteratorType, class TableType>
class const_iterator_pair
{ {
return *reinterpret_cast<const Iterator*>(nullObjectPtr); label size_;
} IteratorType iter_;
public:
inline const_iterator_pair(const TableType& tbl);
inline label size() const;
inline bool empty() const;
inline IteratorType begin() const;
inline IteratorType cbegin() const;
inline const IteratorType& end() const;
inline const IteratorType& cend() const;
};
}; };
@ -131,6 +164,43 @@ class HashTable
: :
public HashTableCore public HashTableCore
{ {
public:
//- The template instance used for this HashTable
typedef HashTable<T, Key, Hash> this_type;
// STL type definitions
//- Type of keys that the HashTable uses.
typedef Key key_type;
//- Type of values that the HashTable contains.
typedef T value_type;
//- The type used for storing into value_type objects.
// This type is usually value_type&.
typedef T& reference;
//- The type used for reading from constant value_type objects.
typedef const T& const_reference;
//- The type to represent the difference between two iterators
typedef label difference_type;
//- The type that can represent the size of a HashTable.
typedef label size_type;
//- Forward iterator with non-const access
class iterator;
//- Forward iterator with const access
class const_iterator;
private:
// Private data type for table entries // Private data type for table entries
//- Structure to hold a hashed entry, with a SLList for collisions //- Structure to hold a hashed entry, with a SLList for collisions
@ -148,7 +218,6 @@ class HashTable
//- Construct from key, next pointer and object //- Construct from key, next pointer and object
inline hashedEntry(const Key& key, const T& obj, hashedEntry* next); inline hashedEntry(const Key& key, const T& obj, hashedEntry* next);
private: private:
//- Disallow default bitwise copy construct //- Disallow default bitwise copy construct
hashedEntry(const hashedEntry&) = delete; hashedEntry(const hashedEntry&) = delete;
@ -183,6 +252,13 @@ class HashTable
protected: protected:
//- Internally used base for iterator and const_iterator
class iterator_base;
//- Friendship with the iterator_base is required.
friend class iterator_base;
// Protected Member Functions // Protected Member Functions
//- Remove using begin/end iterators of listed keys //- Remove using begin/end iterators of listed keys
@ -196,16 +272,6 @@ protected:
public: public:
// Forward declaration of iterators
class iteratorBase;
class iterator;
class const_iterator;
//- Declare friendship with the iteratorBase
friend class iteratorBase;
// Constructors // Constructors
//- Construct given initial table size //- Construct given initial table size
@ -230,92 +296,92 @@ public:
// Member Functions // Member Functions
// Access // Access
//- The size of the underlying table //- The size of the underlying table
inline label capacity() const; inline label capacity() const;
//- Return number of elements in table //- Return number of elements in table
inline label size() const; inline label size() const;
//- Return true if the hash table is empty //- Return true if the hash table is empty
inline bool empty() const; inline bool empty() const;
//- Return true if hashedEntry is found in table //- Return true if hashedEntry is found in table
bool found(const Key& key) const; bool found(const Key& key) const;
//- Find and return an iterator set at the hashedEntry //- Find and return an iterator set at the hashedEntry
// If not found iterator = end() // If not found iterator = end()
iterator find(const Key& key); iterator find(const Key& key);
//- Find and return an const_iterator set at the hashedEntry //- Find and return an const_iterator set at the hashedEntry
// If not found iterator = end() // If not found iterator = end()
const_iterator find(const Key& key) const; const_iterator find(const Key& key) const;
//- Return the table of contents //- Return the table of contents
List<Key> toc() const; List<Key> toc() const;
//- Return the table of contents as a sorted list //- Return the table of contents as a sorted list
List<Key> sortedToc() const; List<Key> sortedToc() const;
// Edit // Edit
//- Insert a new hashedEntry //- Insert a new hashedEntry
// Return true if the entry inserted, which means that it did // Return true if the entry inserted, which means that it did
// not previously exist in the table. // not previously exist in the table.
inline bool insert(const Key& key, const T& newEntry); inline bool insert(const Key& key, const T& newEntry);
//- Assign a new hashedEntry, overwriting existing entries. //- Assign a new hashedEntry, overwriting existing entries.
// Returns true. // Returns true.
inline bool set(const Key& key, const T& newEntry); inline bool set(const Key& key, const T& newEntry);
//- Erase a hashedEntry specified by given iterator //- Erase a hashedEntry specified by given iterator
// This invalidates the iterator until the next operator++ // This invalidates the iterator until the next ++ operation
bool erase(const iterator& iter); bool erase(const iterator& iter);
//- Erase a hashedEntry specified by the given key //- Erase a hashedEntry specified by the given key
bool erase(const Key& key); bool erase(const Key& key);
//- Remove entries given by the listed keys from this HashTable //- Remove entries given by the listed keys from this HashTable
// Return the number of elements removed // Return the number of elements removed
label erase(const UList<Key>& keys); label erase(const UList<Key>& keys);
//- Remove entries given by the listed keys from this HashTable //- Remove entries given by the listed keys from this HashTable
// Return the number of elements removed // Return the number of elements removed
template<unsigned Size> template<unsigned Size>
label erase(const FixedList<Key, Size>& keys); label erase(const FixedList<Key, Size>& keys);
//- Remove entries given by the listed keys from this HashTable //- Remove entries given by the listed keys from this HashTable
// Return the number of elements removed // Return the number of elements removed
label erase(std::initializer_list<Key> keys); label erase(std::initializer_list<Key> keys);
//- Remove entries given by the given keys from this HashTable //- Remove entries given by the given keys from this HashTable
// Return the number of elements removed. // Return the number of elements removed.
// The parameter HashTable needs the same type of key, but the // The parameter HashTable needs the same type of key, but the
// type of values held and the hashing function are arbitrary. // type of values held and the hashing function are arbitrary.
template<class AnyType, class AnyHash> template<class AnyType, class AnyHash>
label erase(const HashTable<AnyType, Key, AnyHash>& other); label erase(const HashTable<AnyType, Key, AnyHash>& other);
//- Resize the hash table for efficiency //- Resize the hash table for efficiency
void resize(const label sz); void resize(const label sz);
//- Clear all entries from table //- Clear all entries from table
void clear(); void clear();
//- Clear the table entries and the table itself. //- Clear the table entries and the table itself.
// Equivalent to clear() followed by resize(0) // Equivalent to clear() followed by resize(0)
void clearStorage(); void clearStorage();
//- Shrink the allocated table to approx. twice number of elements //- Shrink the allocated table to approx. twice number of elements
void shrink(); void shrink();
//- Transfer the contents of the argument table into this table //- Transfer the contents of the argument table into this table
// and annul the argument table. // and annul the argument table.
void transfer(HashTable<T, Key, Hash>& ht); void transfer(HashTable<T, Key, Hash>& ht);
//- Transfer contents to the Xfer container //- Transfer contents to the Xfer container
inline Xfer<HashTable<T, Key, Hash>> xfer(); inline Xfer<HashTable<T, Key, Hash>> xfer();
// Member Operators // Member Operators
@ -345,65 +411,25 @@ public:
bool operator!=(const HashTable<T, Key, Hash>& rhs) const; bool operator!=(const HashTable<T, Key, Hash>& rhs) const;
// STL type definitions protected:
//- Type of keys that the HashTable uses.
typedef Key key_type;
//- Type of values that the HashTable contains.
typedef T value_type;
//- Type that can be used for storing into HashTable::value_type
// objects. This type is usually List::value_type&.
typedef T& reference;
//- Type that can be used for storing into constant
// HashTable::value_type objects. This type is usually const
// HashTable::value_type&.
typedef const T& const_reference;
//- The type that can represent the size of a HashTable.
typedef label size_type;
// Iterator access
//- Iterator set to the beginning of the HashTable
inline iterator begin();
//- const_iterator set to the beginning of the HashTable
inline const_iterator begin() const;
//- const_iterator set to the beginning of the HashTable
inline const_iterator cbegin() const;
//- iterator to signal the end for any HashTable
inline const iterator& end();
//- const_iterator to signal the end for any HashTable
inline const const_iterator& end() const;
//- const_iterator to signal the end for any HashTable
inline const const_iterator& cend() const;
// Iterators and helpers // Iterators and helpers
//- The iterator base for HashTable //- The iterator base for HashTable (internal use only).
// Note: data and functions are protected, to allow reuse by iterator // Note: data and functions are protected, to allow reuse by iterator
// and prevent most external usage. // and prevent most external usage.
// iterator and const_iterator have the same size, allowing // iterator and const_iterator have the same size, allowing
// us to reinterpret_cast between them (if desired) // us to reinterpret_cast between them (if desired)
class iteratorBase class iterator_base
{ {
using entry_type = hashedEntry;
public: public:
// Public typedefs // Public typedefs
using table_type = HashTable<T, Key, Hash>; using table_type = this_type;
using key_type = HashTable<T, Key, Hash>::key_type; using key_type = this_type::key_type;
using difference_type = this_type::difference_type;
private: private:
using entry_type = hashedEntry;
// Private Data // Private Data
@ -428,25 +454,25 @@ public:
//- Increment to the next position //- Increment to the next position
inline void increment(); inline void increment();
//- Erase the entry at the current position
bool erase();
//- The referenced object/value element //- The referenced object/value element
inline T& element() const; inline T& element() const;
//- Erase the entry at the current position
bool erase();
public: public:
// Constructors // Constructors
//- Construct null (end iterator) //- Construct null (end iterator)
inline iteratorBase(); inline iterator_base();
//- Construct from begin of hash-table //- Construct from begin of hash-table
inline explicit iteratorBase(const table_type* hashTbl); inline explicit iterator_base(const table_type* hashTbl);
//- Construct from hash table, element and hash index //- Construct from hash table, element and hash index
inline iteratorBase inline iterator_base
( (
const table_type* hashTbl, const table_type* hashTbl,
const entry_type* elmt, const entry_type* elmt,
@ -463,27 +489,49 @@ public:
inline const Key& key() const; inline const Key& key() const;
//- Compare hash-entry element pointers //- Compare hash-entry element pointers
inline bool operator==(const iteratorBase& iter) const; inline bool operator==(const iterator_base& iter) const;
inline bool operator!=(const iteratorBase& iter) const; inline bool operator!=(const iterator_base& iter) const;
}; };
public:
//- An iterator wrapper for returning a reference to the key
template<class WrappedIterator>
class key_iterator_base
:
public WrappedIterator
{
public:
using reference = const Key&;
using difference_type = typename WrappedIterator::difference_type;
//- Implicit conversion
inline key_iterator_base(const WrappedIterator& iter);
//- Return the key
inline reference operator*() const;
};
// STL iterator // STL iterator
//- An STL-conforming iterator //- Forward iterator with non-const access
class iterator class iterator
: :
public iteratorBase public iterator_base
{ {
friend class HashTable; // uses iterator::erase() method friend class HashTable; // Uses iterator::erase() method
using entry_type = hashedEntry; using entry_type = hashedEntry;
public: public:
// Public typedefs // Public typedefs
using table_type = HashTable<T, Key, Hash>; using table_type = this_type;
using key_type = HashTable<T, Key, Hash>::key_type; using key_type = this_type::key_type;
using reference = HashTable<T, Key, Hash>::reference; using reference = this_type::reference;
using difference_type = typename iterator_base::difference_type;
// Constructors // Constructors
@ -518,19 +566,20 @@ public:
// STL const_iterator // STL const_iterator
//- An STL-conforming const_iterator //- Forward iterator with const access
class const_iterator class const_iterator
: :
public iteratorBase public iterator_base
{ {
using entry_type = const hashedEntry; using entry_type = const hashedEntry;
public: public:
// Public typedefs // Public typedefs
using table_type = const HashTable<T, Key, Hash>; using table_type = const this_type;
using key_type = HashTable<T, Key, Hash>::key_type; using key_type = this_type::key_type;
using reference = HashTable<T, Key, Hash>::const_reference; using reference = this_type::const_reference;
using difference_type = typename iterator_base::difference_type;
// Constructors // Constructors
@ -566,6 +615,43 @@ public:
}; };
//- Iterating over keys only
//- Forward iterator returning the key
using key_iterator = key_iterator_base<iterator>;
//- Forward const iterator returning the key
using const_key_iterator = key_iterator_base<const_iterator>;
//- A const iterator begin/end pair for iterating over keys
const_iterator_pair<const_key_iterator, this_type> keys() const
{
return
const_iterator_pair<const_key_iterator,this_type>(*this);
}
// Iterator access
//- Iterator set to the beginning of the HashTable
inline iterator begin();
//- const_iterator set to the beginning of the HashTable
inline const_iterator begin() const;
//- const_iterator set to the beginning of the HashTable
inline const_iterator cbegin() const;
//- iterator to signal the end for any HashTable
inline const iterator& end();
//- const_iterator to signal the end for any HashTable
inline const const_iterator& end() const;
//- const_iterator to signal the end for any HashTable
inline const const_iterator& cend() const;
// Writing // Writing
//- Print information //- Print information
@ -598,6 +684,7 @@ public:
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#include "HashTableCoreI.H"
#include "HashTableI.H" #include "HashTableI.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

View File

@ -3,7 +3,7 @@
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | \\ / O peration |
\\ / A nd | Copyright (C) 2011-2012 OpenFOAM Foundation \\ / A nd | Copyright (C) 2011-2012 OpenFOAM Foundation
\\/ M anipulation | \\/ M anipulation | Copyright (C) 2017 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -33,38 +33,53 @@ namespace Foam
defineTypeNameAndDebug(HashTableCore, 0); defineTypeNameAndDebug(HashTableCore, 0);
} }
const Foam::label Foam::HashTableCore::maxTableSize
( // Approximately labelMax/4
Foam::HashTableCore::canonicalSize const Foam::label Foam::HashTableCore::maxTableSize(1 << (sizeof(label)*8-3));
(
Foam::labelMax/2
)
);
// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
Foam::label Foam::HashTableCore::canonicalSize(const label size) Foam::label Foam::HashTableCore::canonicalSize(const label requested_size)
{ {
if (size < 1) if (requested_size < 1)
{ {
return 0; return 0;
} }
// enforce power of two // Enforce power of two - makes for a vey fast modulus etc.
uLabel goodSize = size; // Use unsigned for these calculations.
//
// - The lower limit (8) is somewhat arbitrary, but if the hash table
// is too small, there will be many direct table collisions.
// - The uper limit (approx. labelMax/4) must be a power of two,
// need not be extremely large for hashing.
if (goodSize & (goodSize - 1)) uLabel powerOfTwo = 8; // lower-limit
const uLabel size = requested_size;
if (size < powerOfTwo)
{ {
// brute-force is fast enough return powerOfTwo;
goodSize = 1;
while (goodSize < unsigned(size))
{
goodSize <<= 1;
}
} }
else if (requested_size >= maxTableSize)
{
return maxTableSize;
}
else if (size & (size-1)) // <- Modulus of i^2
{
// Determine power-of-two. Brute-force is fast enough.
while (powerOfTwo < size)
{
powerOfTwo <<= 1;
}
return goodSize; return powerOfTwo;
}
else
{
return size;
}
} }

View File

@ -0,0 +1,146 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2017 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 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/>.
\*---------------------------------------------------------------------------*/
// * * * * * * * * * * * * * * * helper methods * * * * * * * * * * * * * * //
template<class IteratorType, class TableType>
inline IteratorType Foam::HashTableCore::iterator_begin
(
TableType& table
)
{
return IteratorType(table.begin());
}
template<class IteratorType, class TableType>
inline IteratorType Foam::HashTableCore::iterator_begin
(
const TableType& table
)
{
return IteratorType(table.begin());
}
template<class IteratorType, class TableType>
inline IteratorType Foam::HashTableCore::iterator_cbegin
(
const TableType& table
)
{
return IteratorType(table.cbegin());
}
template<class IteratorType>
inline const IteratorType& Foam::HashTableCore::iterator_end()
{
return *reinterpret_cast<const IteratorType*>(nullObjectPtr);
}
template<class IteratorType>
inline const IteratorType& Foam::HashTableCore::iterator_cend()
{
return *reinterpret_cast<const IteratorType*>(nullObjectPtr);
}
// * * * * * * * * * * * * * const iterator pair * * * * * * * * * * * * * * //
template<class IteratorType, class TableType>
inline Foam::HashTableCore::const_iterator_pair<IteratorType, TableType>
::const_iterator_pair
(
const TableType& tbl
)
:
size_(tbl.size()),
iter_(tbl.begin())
{}
template<class IteratorType, class TableType>
inline Foam::label
Foam::HashTableCore::const_iterator_pair<IteratorType, TableType>::size() const
{
return size_;
}
template<class IteratorType, class TableType>
inline bool
Foam::HashTableCore::const_iterator_pair<IteratorType, TableType>::empty() const
{
return !size_;
}
template<class IteratorType, class TableType>
inline IteratorType Foam::HashTableCore::const_iterator_pair
<
IteratorType,
TableType
>::begin() const
{
return iter_;
}
template<class IteratorType, class TableType>
inline IteratorType Foam::HashTableCore::const_iterator_pair
<
IteratorType,
TableType
>::cbegin() const
{
return iter_;
}
template<class IteratorType, class TableType>
inline const IteratorType& Foam::HashTableCore::const_iterator_pair
<
IteratorType,
TableType
>::end() const
{
return HashTableCore::iterator_cend<IteratorType>();
}
template<class IteratorType, class TableType>
inline const IteratorType& Foam::HashTableCore::const_iterator_pair
<
IteratorType,
TableType
>::cend() const
{
return HashTableCore::iterator_cend<IteratorType>();
}
// ************************************************************************* //

View File

@ -159,7 +159,7 @@ inline T& Foam::HashTable<T, Key, Hash>::operator()(const Key& key)
// * * * * * * * * * * * * * * * iterator base * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * iterator base * * * * * * * * * * * * * * * //
template<class T, class Key, class Hash> template<class T, class Key, class Hash>
inline Foam::HashTable<T, Key, Hash>::iteratorBase::iteratorBase() inline Foam::HashTable<T, Key, Hash>::iterator_base::iterator_base()
: :
entryPtr_(nullptr), entryPtr_(nullptr),
hashTable_(nullptr), hashTable_(nullptr),
@ -168,7 +168,7 @@ inline Foam::HashTable<T, Key, Hash>::iteratorBase::iteratorBase()
template<class T, class Key, class Hash> template<class T, class Key, class Hash>
inline Foam::HashTable<T, Key, Hash>::iteratorBase::iteratorBase inline Foam::HashTable<T, Key, Hash>::iterator_base::iterator_base
( (
const table_type* hashTbl, const table_type* hashTbl,
const entry_type* elmt, const entry_type* elmt,
@ -182,7 +182,7 @@ inline Foam::HashTable<T, Key, Hash>::iteratorBase::iteratorBase
template<class T, class Key, class Hash> template<class T, class Key, class Hash>
inline Foam::HashTable<T, Key, Hash>::iteratorBase::iteratorBase inline Foam::HashTable<T, Key, Hash>::iterator_base::iterator_base
( (
const table_type* hashTbl const table_type* hashTbl
) )
@ -213,7 +213,7 @@ inline Foam::HashTable<T, Key, Hash>::iteratorBase::iteratorBase
template<class T, class Key, class Hash> template<class T, class Key, class Hash>
inline void inline void
Foam::HashTable<T, Key, Hash>::iteratorBase::increment() Foam::HashTable<T, Key, Hash>::iterator_base::increment()
{ {
// A negative index is a special value from erase // A negative index is a special value from erase
if (hashIndex_ < 0) if (hashIndex_ < 0)
@ -257,30 +257,30 @@ Foam::HashTable<T, Key, Hash>::iteratorBase::increment()
template<class T, class Key, class Hash> template<class T, class Key, class Hash>
inline bool inline bool
Foam::HashTable<T, Key, Hash>::iteratorBase::found() const Foam::HashTable<T, Key, Hash>::iterator_base::found() const
{ {
return entryPtr_; return entryPtr_;
} }
template<class T, class Key, class Hash> template<class T, class Key, class Hash>
inline const Key& Foam::HashTable<T, Key, Hash>::iteratorBase::key() const inline const Key& Foam::HashTable<T, Key, Hash>::iterator_base::key() const
{ {
return entryPtr_->key_; return entryPtr_->key_;
} }
template<class T, class Key, class Hash> template<class T, class Key, class Hash>
inline T& Foam::HashTable<T, Key, Hash>::iteratorBase::element() const inline T& Foam::HashTable<T, Key, Hash>::iterator_base::element() const
{ {
return entryPtr_->obj_; return entryPtr_->obj_;
} }
template<class T, class Key, class Hash> template<class T, class Key, class Hash>
inline bool Foam::HashTable<T, Key, Hash>::iteratorBase::operator== inline bool Foam::HashTable<T, Key, Hash>::iterator_base::operator==
( (
const iteratorBase& iter const iterator_base& iter
) const ) const
{ {
return entryPtr_ == iter.entryPtr_; return entryPtr_ == iter.entryPtr_;
@ -288,21 +288,45 @@ inline bool Foam::HashTable<T, Key, Hash>::iteratorBase::operator==
template<class T, class Key, class Hash> template<class T, class Key, class Hash>
inline bool Foam::HashTable<T, Key, Hash>::iteratorBase::operator!= inline bool Foam::HashTable<T, Key, Hash>::iterator_base::operator!=
( (
const iteratorBase& iter const iterator_base& iter
) const ) const
{ {
return entryPtr_ != iter.entryPtr_; return entryPtr_ != iter.entryPtr_;
} }
// * * * * * * * * * * * * * * key iterator base * * * * * * * * * * * * * * //
template<class T, class Key, class Hash>
template<class WrappedIterator>
inline Foam::HashTable<T, Key, Hash>::key_iterator_base<WrappedIterator>
::key_iterator_base
(
const WrappedIterator& iter
)
:
WrappedIterator(iter)
{}
template<class T, class Key, class Hash>
template<class WrappedIterator>
inline const Key&
Foam::HashTable<T, Key, Hash>::key_iterator_base<WrappedIterator>
::operator*() const
{
return this->key();
}
// * * * * * * * * * * * * * * * * STL iterator * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * STL iterator * * * * * * * * * * * * * * //
template<class T, class Key, class Hash> template<class T, class Key, class Hash>
inline Foam::HashTable<T, Key, Hash>::iterator::iterator() inline Foam::HashTable<T, Key, Hash>::iterator::iterator()
: :
iteratorBase() iterator_base()
{} {}
@ -312,7 +336,7 @@ inline Foam::HashTable<T, Key, Hash>::iterator::iterator
table_type* hashTbl table_type* hashTbl
) )
: :
iteratorBase(hashTbl) iterator_base(hashTbl)
{} {}
@ -324,7 +348,7 @@ inline Foam::HashTable<T, Key, Hash>::iterator::iterator
const label hashIndex const label hashIndex
) )
: :
iteratorBase(hashTbl, elmt, hashIndex) iterator_base(hashTbl, elmt, hashIndex)
{} {}
@ -371,12 +395,12 @@ Foam::HashTable<T, Key, Hash>::iterator::operator++(int)
} }
// * * * * * * * * * * * * * * * STL const_iterator * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * STL const_iterator * * * * * * * * * * * * //
template<class T, class Key, class Hash> template<class T, class Key, class Hash>
inline Foam::HashTable<T, Key, Hash>::const_iterator::const_iterator() inline Foam::HashTable<T, Key, Hash>::const_iterator::const_iterator()
: :
iteratorBase() iterator_base()
{} {}
@ -386,7 +410,7 @@ inline Foam::HashTable<T, Key, Hash>::const_iterator::const_iterator
const HashTable<T, Key, Hash>::iterator& iter const HashTable<T, Key, Hash>::iterator& iter
) )
: :
iteratorBase(iter) iterator_base(iter)
{} {}
@ -396,7 +420,7 @@ inline Foam::HashTable<T, Key, Hash>::const_iterator::const_iterator
table_type* hashTbl table_type* hashTbl
) )
: :
iteratorBase(hashTbl) iterator_base(hashTbl)
{} {}
@ -408,7 +432,7 @@ inline Foam::HashTable<T, Key, Hash>::const_iterator::const_iterator
const label hashIndex const label hashIndex
) )
: :
iteratorBase(hashTbl, elmt, hashIndex) iterator_base(hashTbl, elmt, hashIndex)
{} {}
@ -467,7 +491,7 @@ Foam::HashTable<T, Key, Hash>::begin()
template<class T, class Key, class Hash> template<class T, class Key, class Hash>
inline typename Foam::HashTable<T, Key, Hash>::const_iterator inline typename Foam::HashTable<T, Key, Hash>::const_iterator
Foam::HashTable<T, Key, Hash>::cbegin() const Foam::HashTable<T, Key, Hash>::begin() const
{ {
return const_iterator(this); return const_iterator(this);
} }
@ -475,7 +499,7 @@ Foam::HashTable<T, Key, Hash>::cbegin() const
template<class T, class Key, class Hash> template<class T, class Key, class Hash>
inline typename Foam::HashTable<T, Key, Hash>::const_iterator inline typename Foam::HashTable<T, Key, Hash>::const_iterator
Foam::HashTable<T, Key, Hash>::begin() const Foam::HashTable<T, Key, Hash>::cbegin() const
{ {
return const_iterator(this); return const_iterator(this);
} }
@ -485,19 +509,7 @@ template<class T, class Key, class Hash>
inline const typename Foam::HashTable<T, Key, Hash>::iterator& inline const typename Foam::HashTable<T, Key, Hash>::iterator&
Foam::HashTable<T, Key, Hash>::end() Foam::HashTable<T, Key, Hash>::end()
{ {
using iter_type = typename HashTable<T, Key, Hash>::iterator; return iterator_end<iterator>();
return endIteratorRef<iter_type>();
}
template<class T, class Key, class Hash>
inline const typename Foam::HashTable<T, Key, Hash>::const_iterator&
Foam::HashTable<T, Key, Hash>::cend() const
{
using iter_type = typename HashTable<T, Key, Hash>::const_iterator;
return endIteratorRef<iter_type>();
} }
@ -505,9 +517,15 @@ template<class T, class Key, class Hash>
inline const typename Foam::HashTable<T, Key, Hash>::const_iterator& inline const typename Foam::HashTable<T, Key, Hash>::const_iterator&
Foam::HashTable<T, Key, Hash>::end() const Foam::HashTable<T, Key, Hash>::end() const
{ {
using iter_type = typename HashTable<T, Key, Hash>::const_iterator; return iterator_end<const_iterator>();
}
return endIteratorRef<iter_type>();
template<class T, class Key, class Hash>
inline const typename Foam::HashTable<T, Key, Hash>::const_iterator&
Foam::HashTable<T, Key, Hash>::cend() const
{
return iterator_cend<const_iterator>();
} }

View File

@ -130,7 +130,7 @@ Foam::Ostream& Foam::HashTable<T, Key, Hash>::writeKeys
} }
// Check state of IOstream // Check state of IOstream
os.check("HashSet<Key>::writeList(Ostream&)"); os.check(FUNCTION_NAME);
return os; return os;
} }
@ -279,7 +279,7 @@ Foam::Ostream& Foam::operator<<
os << token::END_LIST; os << token::END_LIST;
// Check state of IOstream // Check state of IOstream
os.check("Ostream& operator<<(Ostream&, const HashTable&)"); os.check(FUNCTION_NAME);
return os; return os;
} }

View File

@ -78,8 +78,8 @@ template<class T, class Key, class Hash> Ostream& operator<<
//- Template-invariant bits for StaticHashTable //- Template-invariant bits for StaticHashTable
struct StaticHashTableCore struct StaticHashTableCore
{ {
//- Return a canonical (power-of-two) size //- Return a canonical (power-of-two) of the requested size.
static label canonicalSize(const label size); static label canonicalSize(const label requested_size);
//- Construct null //- Construct null
StaticHashTableCore() StaticHashTableCore()

View File

@ -34,30 +34,42 @@ defineTypeNameAndDebug(StaticHashTableCore, 0);
} }
// Approximately labelMax/4
static const Foam::label maxTableSize(1 << (sizeof(Foam::label)*8-3));
// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
Foam::label Foam::StaticHashTableCore::canonicalSize(const label size) Foam::label Foam::StaticHashTableCore::canonicalSize(const label requested_size)
{ {
if (size < 1) if (requested_size < 1)
{ {
return 0; return 0;
} }
// Enforce power of two - makes for a vey fast modulus etc. // Enforce power of two - makes for a vey fast modulus etc.
// The value '8' is some arbitrary lower limit. // Use unsigned for these calculations.
// If the hash table is too small, there will be many table collisions! //
// - The lower limit (8) is somewhat arbitrary, but if the hash table
// is too small, there will be many direct table collisions.
// - The uper limit (approx. labelMax/4) must be a power of two,
// need not be extremely large for hashing.
const uLabel unsigned_size = size; uLabel powerOfTwo = 8; // lower-limit
uLabel powerOfTwo = 8;
const uLabel size = requested_size;
if (size < powerOfTwo) if (size < powerOfTwo)
{ {
return powerOfTwo; return powerOfTwo;
} }
else if (unsigned_size & (unsigned_size-1)) // <- Modulus of i^2 else if (requested_size >= maxTableSize)
{
return maxTableSize;
}
else if (size & (size-1)) // <- Modulus of i^2
{ {
// Determine power-of-two. Brute-force is fast enough. // Determine power-of-two. Brute-force is fast enough.
while (powerOfTwo < unsigned_size) while (powerOfTwo < size)
{ {
powerOfTwo <<= 1; powerOfTwo <<= 1;
} }
@ -66,7 +78,7 @@ Foam::label Foam::StaticHashTableCore::canonicalSize(const label size)
} }
else else
{ {
return unsigned_size; return size;
} }
} }