From 03d180724b67d82714b631d7ce03d8f3513aff0e Mon Sep 17 00:00:00 2001
From: Mark Olesen <Mark.Olesen@esi-group.com>
Date: Thu, 4 May 2017 10:17:18 +0200
Subject: [PATCH] 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())
     {
        ...
     }
---
 applications/test/HashSet/Test-hashSet.C      |   8 +-
 applications/test/HashTable/Test-hashTable.C  |  18 +-
 applications/test/cplusplus1/Make/files       |   3 +
 applications/test/cplusplus1/Make/options     |   2 +
 applications/test/cplusplus1/Test-cpluplus1.C |  88 ++++
 applications/test/pTraits/Test-pTraits.C      |  23 +-
 .../containers/HashTables/HashSet/HashSet.C   |  34 +-
 .../containers/HashTables/HashSet/HashSet.H   |  95 ++--
 .../HashTables/HashTable/HashTable.C          |  10 +-
 .../HashTables/HashTable/HashTable.H          | 413 +++++++++++-------
 .../HashTables/HashTable/HashTableCore.C      |  53 ++-
 .../HashTables/HashTable/HashTableCoreI.H     | 146 +++++++
 .../HashTables/HashTable/HashTableI.H         |  82 ++--
 .../HashTables/HashTable/HashTableIO.C        |   4 +-
 .../StaticHashTable/StaticHashTable.H         |   4 +-
 .../StaticHashTable/StaticHashTableCore.C     |  30 +-
 16 files changed, 706 insertions(+), 307 deletions(-)
 create mode 100644 applications/test/cplusplus1/Make/files
 create mode 100644 applications/test/cplusplus1/Make/options
 create mode 100644 applications/test/cplusplus1/Test-cpluplus1.C
 create mode 100644 src/OpenFOAM/containers/HashTables/HashTable/HashTableCoreI.H

diff --git a/applications/test/HashSet/Test-hashSet.C b/applications/test/HashSet/Test-hashSet.C
index fdfecaa08c6..0b219f2e3d1 100644
--- a/applications/test/HashSet/Test-hashSet.C
+++ b/applications/test/HashSet/Test-hashSet.C
@@ -69,6 +69,12 @@ int main(int argc, char *argv[])
 
     Info<< "tableA keys: "; tableA.writeKeys(Info) << endl;
 
+    auto keyIterPair = tableA.keys();
+    for (const auto& i : keyIterPair)
+    {
+        Info<<" keys: " << i << endl;
+    }
+
     Map<label> mapA
     {
         { 1, 1 },
@@ -193,7 +199,7 @@ int main(int argc, char *argv[])
 
     Info<< "setD : " << flatOutput(setD) << endl;
 
-    // this doesn't work (yet?)
+    // This should not work (yet?)
     // setD[12] = true;
 
     List<label> someLst(10);
diff --git a/applications/test/HashTable/Test-hashTable.C b/applications/test/HashTable/Test-hashTable.C
index ad43b6ed9bd..31bff05b0f8 100644
--- a/applications/test/HashTable/Test-hashTable.C
+++ b/applications/test/HashTable/Test-hashTable.C
@@ -24,6 +24,7 @@ License
 \*---------------------------------------------------------------------------*/
 
 #include "HashTable.H"
+#include "List.H"
 #include "IOstreams.H"
 #include "IStringStream.H"
 #include "OStringStream.H"
@@ -177,12 +178,23 @@ int main()
 
     Info<< "\ntable1" << table1 << nl;
 
-    Info<< "\nrange-for(table1)" << nl;
-    for (auto const& it : table1)
+    Info<< "\nrange-for(table1) - returns values" << nl;
+    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";
 
     return 0;
diff --git a/applications/test/cplusplus1/Make/files b/applications/test/cplusplus1/Make/files
new file mode 100644
index 00000000000..8beb3b204c5
--- /dev/null
+++ b/applications/test/cplusplus1/Make/files
@@ -0,0 +1,3 @@
+Test-cpluplus1.C
+
+EXE = $(FOAM_USER_APPBIN)/Test-cpluplus1
diff --git a/applications/test/cplusplus1/Make/options b/applications/test/cplusplus1/Make/options
new file mode 100644
index 00000000000..6a9e9810b3d
--- /dev/null
+++ b/applications/test/cplusplus1/Make/options
@@ -0,0 +1,2 @@
+/* EXE_INC = -I$(LIB_SRC)/cfdTools/include */
+/* EXE_LIBS = -lfiniteVolume */
diff --git a/applications/test/cplusplus1/Test-cpluplus1.C b/applications/test/cplusplus1/Test-cpluplus1.C
new file mode 100644
index 00000000000..b288e9286cc
--- /dev/null
+++ b/applications/test/cplusplus1/Test-cpluplus1.C
@@ -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;
+}
+
+
+// ************************************************************************* //
diff --git a/applications/test/pTraits/Test-pTraits.C b/applications/test/pTraits/Test-pTraits.C
index a914911d293..d300ddc87a5 100644
--- a/applications/test/pTraits/Test-pTraits.C
+++ b/applications/test/pTraits/Test-pTraits.C
@@ -29,6 +29,9 @@ Description
 #include "pTraits.H"
 #include "vector.H"
 #include "tensor.H"
+#include "uLabel.H"
+
+#include <type_traits>
 
 using namespace Foam;
 
@@ -40,7 +43,10 @@ void printTraits()
 {
     Info<< pTraits<T>::typeName
         << ": 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();
     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;
 
     return 0;
diff --git a/src/OpenFOAM/containers/HashTables/HashSet/HashSet.C b/src/OpenFOAM/containers/HashTables/HashSet/HashSet.C
index 5c1b5798299..321b8dd5dfe 100644
--- a/src/OpenFOAM/containers/HashTables/HashSet/HashSet.C
+++ b/src/OpenFOAM/containers/HashTables/HashSet/HashSet.C
@@ -140,6 +140,7 @@ Foam::label Foam::HashSet<Key, Hash>::insert(const UList<Key>& lst)
     return insertMultiple(lst.begin(), lst.end());
 }
 
+
 template<class Key, class Hash>
 template<unsigned Size>
 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());
 }
 
+
 template<class Key, class Hash>
 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>
 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;
 }
 
+
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
 template<class Key, class Hash>
 inline typename Foam::HashSet<Key, Hash>::iterator
 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>
 inline typename Foam::HashSet<Key, Hash>::const_iterator
 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>
 inline typename Foam::HashSet<Key, Hash>::const_iterator
 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>
 inline const typename Foam::HashSet<Key, Hash>::iterator&
 Foam::HashSet<Key, Hash>::end()
 {
-    using iter_type = typename HashSet<Key, Hash>::iterator;
-    return HashTableCore::endIteratorRef<iter_type>();
+    return HashTableCore::iterator_end<iterator>();
 }
 
+
 template<class Key, class Hash>
 inline const typename Foam::HashSet<Key, Hash>::const_iterator&
 Foam::HashSet<Key, Hash>::end() const
 {
-    using iter_type = typename HashSet<Key, Hash>::const_iterator;
-    return HashTableCore::endIteratorRef<iter_type>();
+    return HashTableCore::iterator_end<const_iterator>();
 }
 
+
 template<class Key, class Hash>
 inline const typename Foam::HashSet<Key, Hash>::const_iterator&
 Foam::HashSet<Key, Hash>::cend() const
 {
-    using iter_type = typename HashSet<Key, Hash>::const_iterator;
-    return HashTableCore::endIteratorRef<iter_type>();
+    return HashTableCore::iterator_cend<const_iterator>();
 }
 
 
diff --git a/src/OpenFOAM/containers/HashTables/HashSet/HashSet.H b/src/OpenFOAM/containers/HashTables/HashSet/HashSet.H
index f7f780fe715..300fc111325 100644
--- a/src/OpenFOAM/containers/HashTables/HashSet/HashSet.H
+++ b/src/OpenFOAM/containers/HashTables/HashSet/HashSet.H
@@ -68,8 +68,6 @@ class HashSet
 :
     public HashTable<nil, Key, Hash>
 {
-    typedef HashTable<nil, Key, Hash> ParentClass;
-
     // Private Member Functions
 
         //- Insert values, using begin/end iterators.
@@ -92,18 +90,31 @@ class HashSet
 
 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
 
         //- Construct given initial size
         HashSet(const label size = 128)
         :
-            ParentClass(size)
+            parent_type(size)
         {}
 
         //- Construct from Istream
         HashSet(Istream& is)
         :
-            ParentClass(is)
+            parent_type(is)
         {}
 
         //- Construct from UList of Key
@@ -119,19 +130,19 @@ public:
         //- Construct as copy
         HashSet(const HashSet<Key, Hash>& hs)
         :
-            ParentClass(hs)
+            parent_type(hs)
         {}
 
         //- Construct by transferring the parameter contents
         HashSet(const Xfer<HashSet<Key, Hash>>& hs)
         :
-            ParentClass(hs)
+            parent_type(hs)
         {}
 
         //- Construct by transferring the parameter contents
         HashSet(const Xfer<HashTable<nil, Key, Hash>>& hs)
         :
-            HashTable<nil, Key, Hash>(hs)
+            parent_type(hs)
         {}
 
         //- Construct from the keys of another HashTable,
@@ -147,7 +158,7 @@ public:
         //- Insert a new entry
         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
@@ -191,77 +202,38 @@ public:
         //- Unset the specified key - same as erase
         bool unset(const Key& key)
         {
-            return this->ParentClass::erase(key);
+            return this->parent_type::erase(key);
         }
 
         //- Unset the listed keys - same as erase
         label unset(const UList<Key>& lst)
         {
-            return this->ParentClass::erase(lst);
+            return this->parent_type::erase(lst);
         }
 
         //- Unset the listed keys - same as erase
         template<unsigned Size>
         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
         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
-        struct iterator
-        :
-            public ParentClass::iterator
-        {
-            using parent = typename ParentClass::iterator;
-
-            //- Implicit conversion
-            iterator(const parent& iter)
-            :
-                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;
+        iterator begin();
+        const_iterator begin() const;
+        const_iterator cbegin() const;
 
-            //- 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&;
+        const iterator& end();
+        const const_iterator& end() const;
+        const const_iterator& cend() const;
 
 
     // Writing
@@ -276,15 +248,18 @@ public:
 
     // 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()
         inline bool operator[](const Key& key) const;
 
         //- Equality. Two hashset are equal when they have the same keys.
         //  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.
-        bool operator!=(const HashSet<Key, Hash>& rhs) const;
+        bool operator!=(const this_type& rhs) const;
 
 
         //- Assignment from a UList of keys
diff --git a/src/OpenFOAM/containers/HashTables/HashTable/HashTable.C b/src/OpenFOAM/containers/HashTables/HashTable/HashTable.C
index db3256bcb1c..6e7349d6fac 100644
--- a/src/OpenFOAM/containers/HashTables/HashTable/HashTable.C
+++ b/src/OpenFOAM/containers/HashTables/HashTable/HashTable.C
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
-     \\/     M anipulation  |
+     \\/     M anipulation  | Copyright (C) 2017 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -336,7 +336,7 @@ bool Foam::HashTable<T, Key, Hash>::set
 
 
 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
     if (entryPtr_)
@@ -515,7 +515,7 @@ void Foam::HashTable<T, Key, Hash>::resize(const label sz)
 
     for (const_iterator iter = cbegin(); iter != cend(); ++iter)
     {
-        tmpTable->insert(iter.key(), *iter);
+        tmpTable->insert(iter.key(), iter.object());
     }
 
     const label oldSize = tableSize_;
@@ -645,7 +645,7 @@ void Foam::HashTable<T, Key, Hash>::operator=
         clear();
     }
 
-    for (const Tuple2<Key, T>& pair : lst)
+    for (const auto& pair : lst)
     {
         insert(pair.first(), pair.second());
     }
@@ -684,7 +684,7 @@ bool Foam::HashTable<T, Key, Hash>::operator!=
     const HashTable<T, Key, Hash>& rhs
 ) const
 {
-    return !(operator==(rhs));
+    return !operator==(rhs);
 }
 
 
diff --git a/src/OpenFOAM/containers/HashTables/HashTable/HashTable.H b/src/OpenFOAM/containers/HashTables/HashTable/HashTable.H
index adc3f0aa744..26a7460ee5a 100644
--- a/src/OpenFOAM/containers/HashTables/HashTable/HashTable.H
+++ b/src/OpenFOAM/containers/HashTables/HashTable/HashTable.H
@@ -34,6 +34,13 @@ Note
     often result in a different hash order. Use a sorted table-of-contents
     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
     HashTableI.H
     HashTable.C
@@ -78,25 +85,15 @@ Ostream& operator<<(Ostream& os, const HashTable<T, Key, Hash>& tbl);
                         Class HashTableCore Declaration
 \*---------------------------------------------------------------------------*/
 
-//- Template-invariant bits for HashTable.
-//  This also includes a global end-iterator.
-//
-// 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
+//- Bits that are independent of the HashTable template parameters.
+struct HashTableCore
 {
-public:
-
-    //- Return a canonical (power-of-two) size
-    static label canonicalSize(const label size);
-
-    //- Maximum allowable table size
+    //- Maximum allowable internal table size. Approximately labelMax/4
     static const label maxTableSize;
 
+    //- Return a canonical (power-of-two) of the requested size.
+    static label canonicalSize(const label requested_size);
+
     //- Construct null
     HashTableCore()
     {}
@@ -104,21 +101,57 @@ public:
     //- Define template name and debug
     ClassName("HashTable");
 
-
-protected:
-
     static_assert
     (
         sizeof(NullObject) >= sizeof(void*),
         "NullObject is too small to reinterpret_cast as HashTable::iterator"
     );
 
-    //- Reinterpret a NullObject as a hash-table iterator.
-    template<class Iterator>
-    inline static const Iterator& endIteratorRef()
+
+    //- Factory method to create a non-const iterator begin
+    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:
+
+    //- 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
 
         //- Structure to hold a hashed entry, with a SLList for collisions
@@ -148,7 +218,6 @@ class HashTable
             //- Construct from key, next pointer and object
             inline hashedEntry(const Key& key, const T& obj, hashedEntry* next);
 
-
         private:
             //- Disallow default bitwise copy construct
             hashedEntry(const hashedEntry&) = delete;
@@ -183,6 +252,13 @@ class HashTable
 
 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
 
         //- Remove using begin/end iterators of listed keys
@@ -196,16 +272,6 @@ protected:
 
 public:
 
-    // Forward declaration of iterators
-
-        class iteratorBase;
-        class iterator;
-        class const_iterator;
-
-        //- Declare friendship with the iteratorBase
-        friend class iteratorBase;
-
-
     // Constructors
 
         //- Construct given initial table size
@@ -230,92 +296,92 @@ public:
 
     // Member Functions
 
-        // Access
+      // Access
 
-            //- The size of the underlying table
-            inline label capacity() const;
+        //- The size of the underlying table
+        inline label capacity() const;
 
-            //- Return number of elements in table
-            inline label size() const;
+        //- Return number of elements in table
+        inline label size() const;
 
-            //- Return true if the hash table is empty
-            inline bool empty() const;
+        //- Return true if the hash table is empty
+        inline bool empty() const;
 
-            //- Return true if hashedEntry is found in table
-            bool found(const Key& key) const;
+        //- Return true if hashedEntry is found in table
+        bool found(const Key& key) const;
 
-            //- Find and return an iterator set at the hashedEntry
-            //  If not found iterator = end()
-            iterator find(const Key& key);
+        //- Find and return an iterator set at the hashedEntry
+        //  If not found iterator = end()
+        iterator find(const Key& key);
 
-            //- Find and return an const_iterator set at the hashedEntry
-            //  If not found iterator = end()
-            const_iterator find(const Key& key) const;
+        //- Find and return an const_iterator set at the hashedEntry
+        //  If not found iterator = end()
+        const_iterator find(const Key& key) const;
 
-            //- Return the table of contents
-            List<Key> toc() const;
+        //- Return the table of contents
+        List<Key> toc() const;
 
-            //- Return the table of contents as a sorted list
-            List<Key> sortedToc() const;
+        //- Return the table of contents as a sorted list
+        List<Key> sortedToc() const;
 
 
-        // Edit
+      // Edit
 
-            //- Insert a new hashedEntry
-            //  Return true if the entry inserted, which means that it did
-            //  not previously exist in the table.
-            inline bool insert(const Key& key, const T& newEntry);
+        //- Insert a new hashedEntry
+        //  Return true if the entry inserted, which means that it did
+        //  not previously exist in the table.
+        inline bool insert(const Key& key, const T& newEntry);
 
-            //- Assign a new hashedEntry, overwriting existing entries.
-            //  Returns true.
-            inline bool set(const Key& key, const T& newEntry);
+        //- Assign a new hashedEntry, overwriting existing entries.
+        //  Returns true.
+        inline bool set(const Key& key, const T& newEntry);
 
-            //- Erase a hashedEntry specified by given iterator
-            //  This invalidates the iterator until the next operator++
-            bool erase(const iterator& iter);
+        //- Erase a hashedEntry specified by given iterator
+        //  This invalidates the iterator until the next ++ operation
+        bool erase(const iterator& iter);
 
-            //- Erase a hashedEntry specified by the given key
-            bool erase(const Key& key);
+        //- Erase a hashedEntry specified by the given key
+        bool erase(const Key& key);
 
-            //- Remove entries given by the listed keys from this HashTable
-            //  Return the number of elements removed
-            label erase(const UList<Key>& keys);
+        //- Remove entries given by the listed keys from this HashTable
+        //  Return the number of elements removed
+        label erase(const UList<Key>& keys);
 
-            //- Remove entries given by the listed keys from this HashTable
-            //  Return the number of elements removed
-            template<unsigned Size>
-            label erase(const FixedList<Key, Size>& keys);
+        //- Remove entries given by the listed keys from this HashTable
+        //  Return the number of elements removed
+        template<unsigned Size>
+        label erase(const FixedList<Key, Size>& keys);
 
-            //- Remove entries given by the listed keys from this HashTable
-            //  Return the number of elements removed
-            label erase(std::initializer_list<Key> keys);
+        //- Remove entries given by the listed keys from this HashTable
+        //  Return the number of elements removed
+        label erase(std::initializer_list<Key> keys);
 
-            //- Remove entries given by the given keys from this HashTable
-            //  Return the number of elements removed.
-            //  The parameter HashTable needs the same type of key, but the
-            //  type of values held and the hashing function are arbitrary.
-            template<class AnyType, class AnyHash>
-            label erase(const HashTable<AnyType, Key, AnyHash>& other);
+        //- Remove entries given by the given keys from this HashTable
+        //  Return the number of elements removed.
+        //  The parameter HashTable needs the same type of key, but the
+        //  type of values held and the hashing function are arbitrary.
+        template<class AnyType, class AnyHash>
+        label erase(const HashTable<AnyType, Key, AnyHash>& other);
 
-            //- Resize the hash table for efficiency
-            void resize(const label sz);
+        //- Resize the hash table for efficiency
+        void resize(const label sz);
 
-            //- Clear all entries from table
-            void clear();
+        //- Clear all entries from table
+        void clear();
 
-            //- Clear the table entries and the table itself.
-            //  Equivalent to clear() followed by resize(0)
-            void clearStorage();
+        //- Clear the table entries and the table itself.
+        //  Equivalent to clear() followed by resize(0)
+        void clearStorage();
 
-            //- Shrink the allocated table to approx. twice number of elements
-            void shrink();
+        //- Shrink the allocated table to approx. twice number of elements
+        void shrink();
 
-            //- Transfer the contents of the argument table into this table
-            //  and annul the argument table.
-            void transfer(HashTable<T, Key, Hash>& ht);
+        //- Transfer the contents of the argument table into this table
+        //  and annul the argument table.
+        void transfer(HashTable<T, Key, Hash>& ht);
 
-            //- Transfer contents to the Xfer container
-            inline Xfer<HashTable<T, Key, Hash>> xfer();
+        //- Transfer contents to the Xfer container
+        inline Xfer<HashTable<T, Key, Hash>> xfer();
 
 
     // Member Operators
@@ -345,65 +411,25 @@ public:
         bool operator!=(const HashTable<T, Key, Hash>& rhs) const;
 
 
-    // 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;
-
-        //- 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;
-
+protected:
 
     // 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
         //  and prevent most external usage.
         //  iterator and const_iterator have the same size, allowing
         //  us to reinterpret_cast between them (if desired)
-        class iteratorBase
+        class iterator_base
         {
-            using entry_type = hashedEntry;
-
         public:
             // Public typedefs
-            using table_type = HashTable<T, Key, Hash>;
-            using key_type   = HashTable<T, Key, Hash>::key_type;
+            using table_type = this_type;
+            using key_type   = this_type::key_type;
+            using difference_type  = this_type::difference_type;
 
         private:
+            using entry_type = hashedEntry;
 
           // Private Data
 
@@ -428,25 +454,25 @@ public:
             //- Increment to the next position
             inline void increment();
 
-            //- Erase the entry at the current position
-            bool erase();
-
             //- The referenced object/value element
             inline T& element() const;
 
+            //- Erase the entry at the current position
+            bool erase();
+
 
         public:
 
           // Constructors
 
             //- Construct null (end iterator)
-            inline iteratorBase();
+            inline iterator_base();
 
             //- 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
-            inline iteratorBase
+            inline iterator_base
             (
                 const table_type* hashTbl,
                 const entry_type* elmt,
@@ -463,27 +489,49 @@ public:
             inline const Key& key() const;
 
             //- Compare hash-entry element pointers
-            inline bool operator==(const iteratorBase& iter) const;
-            inline bool operator!=(const iteratorBase& iter) const;
+            inline bool operator==(const iterator_base& 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
 
-        //- An STL-conforming iterator
+        //- Forward iterator with non-const access
         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;
 
         public:
 
           // Public typedefs
-            using table_type = HashTable<T, Key, Hash>;
-            using key_type   = HashTable<T, Key, Hash>::key_type;
-            using reference  = HashTable<T, Key, Hash>::reference;
+            using table_type = this_type;
+            using key_type   = this_type::key_type;
+            using reference  = this_type::reference;
+            using difference_type = typename iterator_base::difference_type;
 
           // Constructors
 
@@ -518,19 +566,20 @@ public:
 
     // STL const_iterator
 
-        //- An STL-conforming const_iterator
+        //- Forward iterator with const access
         class const_iterator
         :
-            public iteratorBase
+            public iterator_base
         {
             using entry_type = const hashedEntry;
 
         public:
 
           // Public typedefs
-            using table_type = const HashTable<T, Key, Hash>;
-            using key_type   = HashTable<T, Key, Hash>::key_type;
-            using reference  = HashTable<T, Key, Hash>::const_reference;
+            using table_type = const this_type;
+            using key_type   = this_type::key_type;
+            using reference  = this_type::const_reference;
+            using difference_type = typename iterator_base::difference_type;
 
           // 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
 
         //- Print information
@@ -598,6 +684,7 @@ public:
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
+#include "HashTableCoreI.H"
 #include "HashTableI.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
diff --git a/src/OpenFOAM/containers/HashTables/HashTable/HashTableCore.C b/src/OpenFOAM/containers/HashTables/HashTable/HashTableCore.C
index 58fcdf27b1c..e57192f1e36 100644
--- a/src/OpenFOAM/containers/HashTables/HashTable/HashTableCore.C
+++ b/src/OpenFOAM/containers/HashTables/HashTable/HashTableCore.C
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2011-2012 OpenFOAM Foundation
-     \\/     M anipulation  |
+     \\/     M anipulation  | Copyright (C) 2017 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -33,38 +33,53 @@ namespace Foam
 defineTypeNameAndDebug(HashTableCore, 0);
 }
 
-const Foam::label Foam::HashTableCore::maxTableSize
-(
-    Foam::HashTableCore::canonicalSize
-    (
-        Foam::labelMax/2
-    )
-);
+
+// Approximately labelMax/4
+const Foam::label Foam::HashTableCore::maxTableSize(1 << (sizeof(label)*8-3));
 
 
 // * * * * * * * * * * * * * * 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;
     }
 
-    // enforce power of two
-    uLabel goodSize = size;
+    // Enforce power of two - makes for a vey fast modulus etc.
+    // 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.
+
+    uLabel powerOfTwo = 8; // lower-limit
 
-    if (goodSize & (goodSize - 1))
+    const uLabel size = requested_size;
+    if (size < powerOfTwo)
+    {
+        return powerOfTwo;
+    }
+    else if (requested_size >= maxTableSize)
+    {
+        return maxTableSize;
+    }
+    else if (size & (size-1))  // <- Modulus of i^2
     {
-        // brute-force is fast enough
-        goodSize = 1;
-        while (goodSize < unsigned(size))
+        // Determine power-of-two. Brute-force is fast enough.
+        while (powerOfTwo < size)
         {
-            goodSize <<= 1;
+            powerOfTwo <<= 1;
         }
-    }
 
-    return goodSize;
+        return powerOfTwo;
+    }
+    else
+    {
+        return size;
+    }
 }
 
 
diff --git a/src/OpenFOAM/containers/HashTables/HashTable/HashTableCoreI.H b/src/OpenFOAM/containers/HashTables/HashTable/HashTableCoreI.H
new file mode 100644
index 00000000000..8198e2e4c33
--- /dev/null
+++ b/src/OpenFOAM/containers/HashTables/HashTable/HashTableCoreI.H
@@ -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>();
+}
+
+
+// ************************************************************************* //
diff --git a/src/OpenFOAM/containers/HashTables/HashTable/HashTableI.H b/src/OpenFOAM/containers/HashTables/HashTable/HashTableI.H
index b3f6276f9ef..f8df2437591 100644
--- a/src/OpenFOAM/containers/HashTables/HashTable/HashTableI.H
+++ b/src/OpenFOAM/containers/HashTables/HashTable/HashTableI.H
@@ -159,7 +159,7 @@ inline T& Foam::HashTable<T, Key, Hash>::operator()(const Key& key)
 // * * * * * * * * * * * * * * * iterator base * * * * * * * * * * * * * * * //
 
 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),
     hashTable_(nullptr),
@@ -168,7 +168,7 @@ inline Foam::HashTable<T, Key, Hash>::iteratorBase::iteratorBase()
 
 
 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 entry_type* elmt,
@@ -182,7 +182,7 @@ inline Foam::HashTable<T, Key, Hash>::iteratorBase::iteratorBase
 
 
 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
 )
@@ -213,7 +213,7 @@ inline Foam::HashTable<T, Key, Hash>::iteratorBase::iteratorBase
 
 template<class T, class Key, class Hash>
 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
     if (hashIndex_ < 0)
@@ -257,30 +257,30 @@ Foam::HashTable<T, Key, Hash>::iteratorBase::increment()
 
 template<class T, class Key, class Hash>
 inline bool
-Foam::HashTable<T, Key, Hash>::iteratorBase::found() const
+Foam::HashTable<T, Key, Hash>::iterator_base::found() const
 {
     return entryPtr_;
 }
 
 
 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_;
 }
 
 
 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_;
 }
 
 
 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
 {
     return entryPtr_ == iter.entryPtr_;
@@ -288,21 +288,45 @@ inline bool Foam::HashTable<T, Key, Hash>::iteratorBase::operator==
 
 
 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
 {
     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  * * * * * * * * * * * * * * //
 
 template<class T, class Key, class Hash>
 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
 )
 :
-    iteratorBase(hashTbl)
+    iterator_base(hashTbl)
 {}
 
 
@@ -324,7 +348,7 @@ inline Foam::HashTable<T, Key, Hash>::iterator::iterator
     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>
 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
 )
 :
-    iteratorBase(iter)
+    iterator_base(iter)
 {}
 
 
@@ -396,7 +420,7 @@ inline Foam::HashTable<T, Key, Hash>::const_iterator::const_iterator
     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
 )
 :
-    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>
 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);
 }
@@ -475,7 +499,7 @@ Foam::HashTable<T, Key, Hash>::cbegin() const
 
 template<class T, class Key, class Hash>
 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);
 }
@@ -485,29 +509,23 @@ template<class T, class Key, class Hash>
 inline const typename Foam::HashTable<T, Key, Hash>::iterator&
 Foam::HashTable<T, Key, Hash>::end()
 {
-    using iter_type = typename HashTable<T, Key, Hash>::iterator;
-
-    return endIteratorRef<iter_type>();
+    return iterator_end<iterator>();
 }
 
 
 template<class T, class Key, class Hash>
 inline const typename Foam::HashTable<T, Key, Hash>::const_iterator&
-Foam::HashTable<T, Key, Hash>::cend() const
+Foam::HashTable<T, Key, Hash>::end() const
 {
-    using iter_type = typename HashTable<T, Key, Hash>::const_iterator;
-
-    return endIteratorRef<iter_type>();
+    return iterator_end<const_iterator>();
 }
 
 
 template<class T, class Key, class Hash>
 inline const typename Foam::HashTable<T, Key, Hash>::const_iterator&
-Foam::HashTable<T, Key, Hash>::end() const
+Foam::HashTable<T, Key, Hash>::cend() const
 {
-    using iter_type = typename HashTable<T, Key, Hash>::const_iterator;
-
-    return endIteratorRef<iter_type>();
+    return iterator_cend<const_iterator>();
 }
 
 
diff --git a/src/OpenFOAM/containers/HashTables/HashTable/HashTableIO.C b/src/OpenFOAM/containers/HashTables/HashTable/HashTableIO.C
index 97193707c16..0eb3fadb459 100644
--- a/src/OpenFOAM/containers/HashTables/HashTable/HashTableIO.C
+++ b/src/OpenFOAM/containers/HashTables/HashTable/HashTableIO.C
@@ -130,7 +130,7 @@ Foam::Ostream& Foam::HashTable<T, Key, Hash>::writeKeys
     }
 
     // Check state of IOstream
-    os.check("HashSet<Key>::writeList(Ostream&)");
+    os.check(FUNCTION_NAME);
 
     return os;
 }
@@ -279,7 +279,7 @@ Foam::Ostream& Foam::operator<<
     os << token::END_LIST;
 
     // Check state of IOstream
-    os.check("Ostream& operator<<(Ostream&, const HashTable&)");
+    os.check(FUNCTION_NAME);
 
     return os;
 }
diff --git a/src/OpenFOAM/containers/HashTables/StaticHashTable/StaticHashTable.H b/src/OpenFOAM/containers/HashTables/StaticHashTable/StaticHashTable.H
index 9614b82fbbe..639a434d654 100644
--- a/src/OpenFOAM/containers/HashTables/StaticHashTable/StaticHashTable.H
+++ b/src/OpenFOAM/containers/HashTables/StaticHashTable/StaticHashTable.H
@@ -78,8 +78,8 @@ template<class T, class Key, class Hash> Ostream& operator<<
 //- Template-invariant bits for StaticHashTable
 struct StaticHashTableCore
 {
-    //- Return a canonical (power-of-two) size
-    static label canonicalSize(const label size);
+    //- Return a canonical (power-of-two) of the requested size.
+    static label canonicalSize(const label requested_size);
 
     //- Construct null
     StaticHashTableCore()
diff --git a/src/OpenFOAM/containers/HashTables/StaticHashTable/StaticHashTableCore.C b/src/OpenFOAM/containers/HashTables/StaticHashTable/StaticHashTableCore.C
index 9f24c86e63a..31c02ebf5ec 100644
--- a/src/OpenFOAM/containers/HashTables/StaticHashTable/StaticHashTableCore.C
+++ b/src/OpenFOAM/containers/HashTables/StaticHashTable/StaticHashTableCore.C
@@ -34,30 +34,42 @@ defineTypeNameAndDebug(StaticHashTableCore, 0);
 }
 
 
+// Approximately labelMax/4
+static const Foam::label maxTableSize(1 << (sizeof(Foam::label)*8-3));
+
+
 // * * * * * * * * * * * * * * 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;
     }
 
     // Enforce power of two - makes for a vey fast modulus etc.
-    // The value '8' is some arbitrary lower limit.
-    // If the hash table is too small, there will be many table collisions!
+    // 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.
 
-    const uLabel unsigned_size = size;
-    uLabel powerOfTwo = 8;
+    uLabel powerOfTwo = 8; // lower-limit
 
+    const uLabel size = requested_size;
     if (size < 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.
-        while (powerOfTwo < unsigned_size)
+        while (powerOfTwo < size)
         {
             powerOfTwo <<= 1;
         }
@@ -66,7 +78,7 @@ Foam::label Foam::StaticHashTableCore::canonicalSize(const label size)
     }
     else
     {
-        return unsigned_size;
+        return size;
     }
 }
 
-- 
GitLab