diff --git a/applications/test/IOobjectList/Make/files b/applications/test/IOobjectList/Make/files
new file mode 100644
index 0000000000000000000000000000000000000000..c09b00ecaaf4c1b9875e168bfb5d87a7a697eca7
--- /dev/null
+++ b/applications/test/IOobjectList/Make/files
@@ -0,0 +1,3 @@
+Test-IOobjectList.C
+
+EXE = $(FOAM_USER_APPBIN)/Test-IOobjectList
diff --git a/applications/test/IOobjectList/Make/options b/applications/test/IOobjectList/Make/options
new file mode 100644
index 0000000000000000000000000000000000000000..d9745f69a080fe0e7e312968c0a3355745247cb0
--- /dev/null
+++ b/applications/test/IOobjectList/Make/options
@@ -0,0 +1,3 @@
+EXE_INC = -I$(LIB_SRC)/finiteVolume/lnInclude
+
+EXE_LIBS = -lfiniteVolume
diff --git a/applications/test/IOobjectList/Test-IOobjectList.C b/applications/test/IOobjectList/Test-IOobjectList.C
new file mode 100644
index 0000000000000000000000000000000000000000..27bd495950638d839550e13b999726ead22daffd
--- /dev/null
+++ b/applications/test/IOobjectList/Test-IOobjectList.C
@@ -0,0 +1,104 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  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
+    Basic tests of IOobjectList
+\*---------------------------------------------------------------------------*/
+
+#include "argList.H"
+#include "Time.H"
+#include "volFields.H"
+#include "timeSelector.H"
+#include "IOobjectList.H"
+#include "hashedWordList.H"
+
+using namespace Foam;
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+// Main program:
+
+int main(int argc, char *argv[])
+{
+    argList::noParallel();
+    argList::addOption("re", "wordReList");
+
+    // timeSelector::addOptions();
+    timeSelector::addOptions(true, true);
+
+    #include "setRootCase.H"
+    #include "createTime.H"
+
+    wordReList matcher;
+    if (args.optionFound("re"))
+    {
+        matcher = args.optionReadList<wordRe>("re");
+        Info<<"limit names: " << matcher << nl;
+
+    }
+
+    const hashedWordList subsetTypes
+    {
+        volScalarField::typeName,
+        volScalarField::Internal::typeName,
+        volVectorField::typeName,
+    };
+
+
+    instantList timeDirs = timeSelector::select0(runTime, args);
+
+    forAll(timeDirs, timeI)
+    {
+        runTime.setTime(timeDirs[timeI], timeI);
+
+        // Objects at this time
+        IOobjectList objects(runTime, runTime.timeName());
+        HashTable<wordHashSet> classes =
+        (
+            matcher.size()
+          ? objects.classes(matcher)
+          : objects.classes()
+        );
+
+        Info<< "Time: " << runTime.timeName() << nl;
+
+        Info<<"Name:    " << flatOutput(objects.sortedNames()) << nl
+            <<"Objects: " << objects << nl
+            <<"Classes: " << classes << nl;
+
+        classes.filterKeys(subsetTypes);
+        Info<<"only retain: " << flatOutput(subsetTypes) << nl;
+        Info<<"Pruned: " << classes << nl;
+
+        classes = objects.classes();
+        classes.erase(subsetTypes);
+        Info<<"remove: " << flatOutput(subsetTypes) << nl;
+        Info<<"Pruned: " << classes << nl;
+    }
+
+    Info<< "\nEnd\n" << endl;
+
+    return 0;
+}
+
+
+// ************************************************************************* //
diff --git a/src/OpenFOAM/db/IOobjectList/IOobjectList.C b/src/OpenFOAM/db/IOobjectList/IOobjectList.C
index 14c68e7b7686467de1a0c9eeba119a1aab95645f..981e5ca2e579dcd38079617c1692c6165fcfa44a 100644
--- a/src/OpenFOAM/db/IOobjectList/IOobjectList.C
+++ b/src/OpenFOAM/db/IOobjectList/IOobjectList.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  | Copyright (C) 2016 OpenCFD Ltd.
+     \\/     M anipulation  | Copyright (C) 2016-2017 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -27,7 +27,99 @@ License
 #include "Time.H"
 #include "OSspecific.H"
 #include "IOList.H"
-#include "stringListOps.H"
+#include "predicates.H"
+
+// * * * * * * * * * * * * * * Static Functions * * * * * * * * * * * * * //
+
+namespace Foam
+{
+    // Templated implementation for lookup() - file-scope
+    template<class UnaryMatchPredicate>
+    static IOobjectList lookupImpl
+    (
+        const IOobjectList& list,
+        const UnaryMatchPredicate& matcher
+    )
+    {
+        IOobjectList results(list.size());
+
+        forAllConstIters(list, iter)
+        {
+            if (matcher(iter.key()))
+            {
+                if (IOobject::debug)
+                {
+                    InfoInFunction << "Found " << iter.key() << endl;
+                }
+
+                results.insert
+                (
+                    iter.key(),
+                    new IOobject(*(iter.object()))
+                );
+            }
+        }
+
+        return results;
+    }
+
+
+    // Templated implementation for classes() - file-scope
+    template<class UnaryMatchPredicate>
+    static HashTable<wordHashSet> classesImpl
+    (
+        const IOobjectList& list,
+        const UnaryMatchPredicate& matcher
+    )
+    {
+        HashTable<wordHashSet> summary(2*list.size());
+
+        // Summary (key,val) = (class-name, object-names)
+        forAllConstIters(list, iter)
+        {
+            if (matcher(iter.key()))
+            {
+                // Create entry (if needed) and insert
+                summary(iter.object()->headerClassName()).insert(iter.key());
+            }
+        }
+
+        return summary;
+    }
+
+
+    // Templated implementation for names(), sortedNames() - file-scope
+    template<class UnaryMatchPredicate>
+    static wordList namesImpl
+    (
+        const IOobjectList& list,
+        const word& clsName,
+        const UnaryMatchPredicate& matcher,
+        const bool doSort
+    )
+    {
+        wordList objNames(list.size());
+
+        label count = 0;
+        forAllConstIters(list, iter)
+        {
+            if (iter()->headerClassName() == clsName && matcher(iter.key()))
+            {
+                objNames[count++] = iter.key();
+            }
+        }
+
+        objNames.setSize(count);
+
+        if (doSort)
+        {
+            Foam::sort(objNames);
+        }
+
+        return objNames;
+    }
+}
+
 
 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
 
@@ -62,14 +154,14 @@ Foam::IOobjectList::IOobjectList
     }
 
     // Create a list of file names in this directory
-    fileNameList ObjectNames =
+    fileNameList objNames =
         readDir(db.path(newInstance, db.dbDir()/local), fileName::FILE);
 
-    forAll(ObjectNames, i)
+    forAll(objNames, i)
     {
         IOobject* objectPtr = new IOobject
         (
-            ObjectNames[i],
+            objNames[i],
             newInstance,
             local,
             db,
@@ -81,7 +173,7 @@ Foam::IOobjectList::IOobjectList
         // Use object with local scope
         if (objectPtr->typeHeaderOk<IOList<label>>(false))
         {
-            insert(ObjectNames[i], objectPtr);
+            insert(objectPtr->name(), objectPtr);
         }
         else
         {
@@ -119,7 +211,7 @@ bool Foam::IOobjectList::remove(IOobject& io)
 
 Foam::IOobject* Foam::IOobjectList::lookup(const word& name) const
 {
-    HashPtrTable<IOobject>::const_iterator iter = find(name);
+    const_iterator iter = find(name);
 
     if (iter.found())
     {
@@ -144,38 +236,23 @@ Foam::IOobject* Foam::IOobjectList::lookup(const word& name) const
 
 Foam::IOobjectList Foam::IOobjectList::lookup(const wordRe& matcher) const
 {
-    IOobjectList results(size());
-
-    forAllConstIters(*this, iter)
-    {
-        if (matcher.match(iter.key()))
-        {
-            if (IOobject::debug)
-            {
-                InfoInFunction << "Found " << iter.key() << endl;
-            }
+    return lookupImpl(*this, matcher);
+}
 
-            results.insert
-            (
-                iter.key(),
-                new IOobject(*(iter.object()))
-            );
-        }
-    }
 
-    return results;
+Foam::IOobjectList Foam::IOobjectList::lookup(const wordRes& matcher) const
+{
+    return lookupImpl(*this, matcher);
 }
 
 
-Foam::IOobjectList Foam::IOobjectList::lookup(const wordReList& matcher) const
+Foam::IOobjectList Foam::IOobjectList::lookupClass(const word& clsName) const
 {
-    wordRes mat(matcher);
-
     IOobjectList results(size());
 
     forAllConstIters(*this, iter)
     {
-        if (mat.match(iter.key()))
+        if (iter()->headerClassName() == clsName)
         {
             if (IOobject::debug)
             {
@@ -194,28 +271,23 @@ Foam::IOobjectList Foam::IOobjectList::lookup(const wordReList& matcher) const
 }
 
 
-Foam::IOobjectList Foam::IOobjectList::lookupClass(const word& clsName) const
+Foam::HashTable<Foam::wordHashSet> Foam::IOobjectList::classes() const
 {
-    IOobjectList results(size());
+    return classesImpl(*this, predicates::always());
+}
 
-    forAllConstIters(*this, iter)
-    {
-        if (iter()->headerClassName() == clsName)
-        {
-            if (IOobject::debug)
-            {
-                InfoInFunction << "Found " << iter.key() << endl;
-            }
 
-            results.insert
-            (
-                iter.key(),
-                new IOobject(*(iter.object()))
-            );
-        }
-    }
+Foam::HashTable<Foam::wordHashSet>
+Foam::IOobjectList::classes(const wordRe& matcher) const
+{
+    return classesImpl(*this, matcher);
+}
 
-    return results;
+
+Foam::HashTable<Foam::wordHashSet>
+Foam::IOobjectList::classes(const wordRes& matcher) const
+{
+    return classesImpl(*this, matcher);
 }
 
 
@@ -236,20 +308,7 @@ Foam::wordList Foam::IOobjectList::names
     const word& clsName
 ) const
 {
-    wordList objNames(size());
-
-    label count = 0;
-    forAllConstIters(*this, iter)
-    {
-        if (iter()->headerClassName() == clsName)
-        {
-            objNames[count++] = iter.key();
-        }
-    }
-
-    objNames.setSize(count);
-
-    return objNames;
+    return namesImpl(*this, clsName, predicates::always(), false);
 }
 
 
@@ -259,21 +318,17 @@ Foam::wordList Foam::IOobjectList::names
     const wordRe& matcher
 ) const
 {
-    wordList objNames = names(clsName);
-
-    return wordList(objNames, findStrings(matcher, objNames));
+    return namesImpl(*this, clsName, matcher, false);
 }
 
 
 Foam::wordList Foam::IOobjectList::names
 (
     const word& clsName,
-    const wordReList& matcher
+    const wordRes& matcher
 ) const
 {
-    wordList objNames = names(clsName);
-
-    return wordList(objNames, findStrings(matcher, objNames));
+    return namesImpl(*this, clsName, matcher, false);
 }
 
 
@@ -282,10 +337,7 @@ Foam::wordList Foam::IOobjectList::sortedNames
     const word& clsName
 ) const
 {
-    wordList sortedLst = names(clsName);
-    sort(sortedLst);
-
-    return sortedLst;
+    return namesImpl(*this, clsName, predicates::always(), true);
 }
 
 
@@ -295,23 +347,35 @@ Foam::wordList Foam::IOobjectList::sortedNames
     const wordRe& matcher
 ) const
 {
-    wordList sortedLst = names(clsName, matcher);
-    sort(sortedLst);
-
-    return sortedLst;
+    return namesImpl(*this, clsName, matcher, true);
 }
 
 
 Foam::wordList Foam::IOobjectList::sortedNames
 (
     const word& clsName,
-    const wordReList& matcher
+    const wordRes& matcher
 ) const
 {
-    wordList sortedLst = names(clsName, matcher);
-    sort(sortedLst);
+    return namesImpl(*this, clsName, matcher, true);
+}
+
+
+// * * * * * * * * * * * * * * * IOstream Operators  * * * * * * * * * * * * //
+
+Foam::Ostream& Foam::operator<<(Ostream& os, const IOobjectList& list)
+{
+    os << nl << list.size() << nl << token::BEGIN_LIST << nl;
+
+    forAllConstIters(list, it)
+    {
+        os << it.key() << token::SPACE << it.object()->headerClassName() << nl;
+    }
+
+    os << token::END_LIST;
+    os.check(FUNCTION_NAME);
 
-    return sortedLst;
+    return os;
 }
 
 
diff --git a/src/OpenFOAM/db/IOobjectList/IOobjectList.H b/src/OpenFOAM/db/IOobjectList/IOobjectList.H
index 17f75233ed38e01385e752c6edbda806477f386f..0976e1540ff6dc7b66add388f755001f7ba7fff7 100644
--- a/src/OpenFOAM/db/IOobjectList/IOobjectList.H
+++ b/src/OpenFOAM/db/IOobjectList/IOobjectList.H
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
-     \\/     M anipulation  | Copyright (C) 2016 OpenCFD Ltd.
+     \\/     M anipulation  | Copyright (C) 2016-2017 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -36,14 +36,20 @@ SourceFiles
 #define IOobjectList_H
 
 #include "HashPtrTable.H"
+#include "HashSet.H"
 #include "IOobject.H"
-#include "wordReList.H"
+#include "wordRes.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
 namespace Foam
 {
 
+// Forward declaration of friend functions and operators
+class IOobjectList;
+Ostream& operator<<(Ostream& os, const IOobjectList& list);
+
+
 /*---------------------------------------------------------------------------*\
                         Class IOobjectList Declaration
 \*---------------------------------------------------------------------------*/
@@ -86,12 +92,17 @@ public:
 
     // Member functions
 
+      // Basic methods
+
         //- Add an IOobject to the list
         bool add(IOobject& io);
 
         //- Remove an IOobject from the list
         bool remove(IOobject& io);
 
+
+      // Lookup
+
         //- Lookup a given name and return IOobject ptr if found else nullptr
         IOobject* lookup(const word& name) const;
 
@@ -99,12 +110,94 @@ public:
         IOobjectList lookup(const wordRe& matcher) const;
 
         //- The list of all IOobjects with matching names
-        IOobjectList lookup(const wordReList& matcher) const;
+        IOobjectList lookup(const wordRes& matcher) const;
 
         //- The list of all IOobjects with the given class name
         IOobjectList lookupClass(const word& clsName) const;
 
 
+      // Summary of classes
+
+        //- A summary hash of classes used and their associated object names.
+        //  The HashTable representation allows us to leverage various
+        //  HashTable methods.
+        //  This hashed summary view can be useful when querying particular
+        //  aspects. For example,
+        //
+        //  \code
+        //  IOobjectList objects(runTime, runTime.timeName());
+        //  HashTable<wordHashSet> classes = objects.classes();
+        //
+        //  // How many volScalarField?
+        //  word checkType = volScalarField::typeName;
+        //
+        //  Info<< checkType << "="
+        //      << (classes.found(checkType) ? classes[checkType].size() : 0)
+        //      << nl;
+        //  \endcode
+        //  Using the two-parameter HashTable::lookup method lets us avoid
+        //  the \c '?' ternary, but still looks fairly ugly:
+        //  \code
+        //  Info<< checkType << "="
+        //      << classes.lookup(checkType, wordHashSet()).size() << nl;
+        //  \endcode
+        //
+        //  If we have non-const access to the hash table, and don't mind
+        //  incidentally creating empty entries,
+        //  we can use the HashTable::operator() directly:
+        //  \code
+        //  Info<< checkType << "=" << classes(checkType).size() << nl;
+        //  \endcode
+        //
+        //  Of course, for a single query it would have been easier
+        //  and simpler to have used a direct query of the names:
+        //  \code
+        //  Info<< checkType << "=" << objects.names(checkType).size() << nl;
+        //  \endcode
+        //
+        //  The summary hash, however, becomes most useful when reducing
+        //  the objects in consideration to a particular subset. For example,
+        //  \code
+        //  const wordHashSet interestingTypes
+        //  {
+        //      volScalarField::typeName,
+        //      volVectorField::typeName
+        //  };
+        //
+        //  classes.retain(interestingTypes);
+        //  \endcode
+        //  Or do just the opposite:
+        //  \code
+        //  classes.erase(unsupportedTypes);
+        //  \endcode
+        //  This also works with a hashedWordList, since it provides the
+        //  expected '()' operator. But in this case the more general
+        //  HashTable::filterKeys is required:
+        //  \code
+        //  const hashedWordList interestingTypes
+        //  {
+        //      volScalarField::typeName,
+        //      volVectorField::typeName
+        //  };
+        //
+        //  classes.filterKeys(interestingTypes);
+        //  \endcode
+        //
+        //  Of course, there are many other ways to use and manipulate the
+        //  summary information.
+        HashTable<wordHashSet> classes() const;
+
+        //- A summary hash of classes used and their associated object names
+        //  restricted to objects with names that satisfy the input matcher
+        HashTable<wordHashSet> classes(const wordRe& matcher) const;
+
+        //- A summary hash of classes used and their associated object names
+        //  restricted to objects with names that satisfy the input matcher
+        HashTable<wordHashSet> classes(const wordRes& matcher) const;
+
+
+      // Summary of names
+
         //- A list of names of the IOobjects
         wordList names() const;
 
@@ -117,9 +210,11 @@ public:
 
         //- The names of IOobjects with the given class name that also
         //  have a name satisfying the input matcher
-        wordList names(const word& clsName, const wordReList& matcher) const;
+        wordList names(const word& clsName, const wordRes& matcher) const;
 
 
+      // Summary of names (sorted)
+
         //- A sorted list of names of the IOobjects
         wordList sortedNames() const;
 
@@ -132,11 +227,12 @@ public:
 
         //- The sorted names of IOobjects with the given class name that also
         //  have a name satisfying the input matcher
-        wordList sortedNames
-        (
-            const word& clsName,
-            const wordReList& matcher
-        ) const;
+        wordList sortedNames(const word& clsName, const wordRes& matcher) const;
+
+
+    // Ostream Operator
+
+        friend Ostream& operator<<(Ostream& os, const IOobjectList& list);
 };
 
 
diff --git a/src/OpenFOAM/db/objectRegistry/objectRegistry.C b/src/OpenFOAM/db/objectRegistry/objectRegistry.C
index d72efda11cab30f7eecb11dbc88e7b807150af8a..2f048ea71c7a5835a1a5999803f2b7f1c783cdb5 100644
--- a/src/OpenFOAM/db/objectRegistry/objectRegistry.C
+++ b/src/OpenFOAM/db/objectRegistry/objectRegistry.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  | Copyright (C) 2015-2016 OpenCFD Ltd.
+     \\/     M anipulation  | Copyright (C) 2015-2017 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -25,6 +25,7 @@ License
 
 #include "objectRegistry.H"
 #include "Time.H"
+#include "predicates.H"
 
 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
 
@@ -103,7 +104,7 @@ Foam::objectRegistry::~objectRegistry()
         }
     }
 
-    for (label i=0; i < nMyObjects; i++)
+    for (label i=0; i < nMyObjects; ++i)
     {
         checkOut(*myObjects[i]);
     }
@@ -112,6 +113,26 @@ Foam::objectRegistry::~objectRegistry()
 
 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
 
+Foam::HashTable<Foam::wordHashSet> Foam::objectRegistry::classes() const
+{
+    return classesImpl(*this, predicates::always());
+}
+
+
+Foam::HashTable<Foam::wordHashSet>
+Foam::objectRegistry::classes(const wordRe& matcher) const
+{
+    return classesImpl(*this, matcher);
+}
+
+
+Foam::HashTable<Foam::wordHashSet>
+Foam::objectRegistry::classes(const wordRes& matcher) const
+{
+    return classesImpl(*this, matcher);
+}
+
+
 Foam::wordList Foam::objectRegistry::names() const
 {
     return HashTable<regIOobject*>::toc();
@@ -124,31 +145,31 @@ Foam::wordList Foam::objectRegistry::sortedNames() const
 }
 
 
-Foam::wordList Foam::objectRegistry::names(const word& ClassName) const
+Foam::wordList Foam::objectRegistry::names(const word& clsName) const
 {
-    wordList objectNames(size());
+    wordList objNames(size());
 
     label count=0;
     for (const_iterator iter = cbegin(); iter != cend(); ++iter)
     {
-        if (iter()->type() == ClassName)
+        if (iter()->type() == clsName)
         {
-            objectNames[count++] = iter.key();
+            objNames[count++] = iter.key();
         }
     }
 
-    objectNames.setSize(count);
+    objNames.setSize(count);
 
-    return objectNames;
+    return objNames;
 }
 
 
-Foam::wordList Foam::objectRegistry::sortedNames(const word& ClassName) const
+Foam::wordList Foam::objectRegistry::sortedNames(const word& clsName) const
 {
-    wordList sortedLst = names(ClassName);
-    sort(sortedLst);
+    wordList objNames = names(clsName);
+    Foam::sort(objNames);
 
-    return sortedLst;
+    return objNames;
 }
 
 
@@ -224,7 +245,7 @@ bool Foam::objectRegistry::checkOut(regIOobject& io) const
 {
     iterator iter = const_cast<objectRegistry&>(*this).find(io.name());
 
-    if (iter != end())
+    if (iter.found())
     {
         if (objectRegistry::debug)
         {
diff --git a/src/OpenFOAM/db/objectRegistry/objectRegistry.H b/src/OpenFOAM/db/objectRegistry/objectRegistry.H
index 16dc0e17780da30f9381c0e8035b73d0e99125b5..77d390754f6aef1aa479644f8cc5dc7ebd06c9ad 100644
--- a/src/OpenFOAM/db/objectRegistry/objectRegistry.H
+++ b/src/OpenFOAM/db/objectRegistry/objectRegistry.H
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
-     \\/     M anipulation  | Copyright (C) 2016 OpenCFD Ltd.
+     \\/     M anipulation  | Copyright (C) 2016-2017 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -37,8 +37,9 @@ SourceFiles
 #define objectRegistry_H
 
 #include "HashTable.H"
+#include "HashSet.H"
 #include "regIOobject.H"
-#include "wordReList.H"
+#include "wordRes.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
@@ -75,6 +76,24 @@ class objectRegistry
         //  Used to terminate searching within the ancestors
         bool parentNotTime() const;
 
+        //- Templated implementation for classes()
+        template<class UnaryMatchPredicate>
+        static HashTable<wordHashSet> classesImpl
+        (
+            const objectRegistry& list,
+            const UnaryMatchPredicate& matcher
+        );
+
+        //- Templated implementation for names()
+        template<class Type, class UnaryMatchPredicate>
+        static wordList namesImpl
+        (
+            const objectRegistry& list,
+            const UnaryMatchPredicate& matcher,
+            const bool doSort
+        );
+
+
         //- Disallow Copy constructor
         objectRegistry(const objectRegistry&) = delete;
 
@@ -113,184 +132,209 @@ public:
 
     // Member functions
 
-        // Access
-
-            //- Return time
-            const Time& time() const
-            {
-                return time_;
-            }
-
-            //- Return the parent objectRegistry
-            const objectRegistry& parent() const
-            {
-                return parent_;
-            }
-
-            //- Local directory path of this objectRegistry relative to the time
-            virtual const fileName& dbDir() const
-            {
-                return dbDir_;
-            }
-
-            //- A list of names of the objects
-            wordList names() const;
-
-            //- A sorted list of names of the objects
-            wordList sortedNames() const;
-
-            //- A list of names of objects that have the given class name
-            wordList names(const word& className) const;
-
-            //- A sorted list of names of objects that have the given class name
-            wordList sortedNames(const word& className) const;
-
-            //- A list of names of objects that have the given type
-            template<class Type>
-            wordList names() const;
-
-            //- A list of names of objects that have the given type,
-            //  and that also satisfy the input matcher
-            template<class Type>
-            wordList names(const wordRe&) const;
-
-            //- A list of names for objects that have the given type,
-            //  and that also satisfy the input matchers
-            template<class Type>
-            wordList names(const wordReList&) const;
-
-            //- A sorted list of names of objects that have the given type
-            template<class Type>
-            wordList sortedNames() const;
-
-            //- A sorted list of names of objects that have the given type,
-            //  and that also satisfy the input matcher
-            template<class Type>
-            wordList sortedNames(const wordRe&) const;
-
-            //- A sorted list of names of objects that have the given type,
-            //  and that also satisfy the input matchers
-            template<class Type>
-            wordList sortedNames(const wordReList&) const;
-
-
-            //- Lookup and return a const sub-objectRegistry.
-            //  Optionally create it if it does not exist.
-            //  If recursive, search parent registries.
-            const objectRegistry& subRegistry
-            (
-                const word& name,
-                const bool forceCreate = false,
-                const bool recursive = false
-            ) const;
-
-
-            //- Lookup and return all objects of the given Type
-            template<class Type>
-            HashTable<const Type*> lookupClass(const bool strict = false) const;
-
-            //- Lookup and return all objects of the given Type
-            template<class Type>
-            HashTable<Type*> lookupClass(const bool strict = false);
-
-            //- Is the named Type found?
-            //  If recursive, search parent registries.
-            template<class Type>
-            bool foundObject
-            (
-                const word& name,
-                const bool recursive = false
-            ) const;
-
-            //- Lookup and return the object of the given Type.
-            //  If recursive, search parent registries.
-            template<class Type>
-            const Type& lookupObject
-            (
-                const word& name,
-                const bool recursive = false
-            ) const;
-
-            //- Lookup and return the object of the given Type.
-            //  If recursive, search parent registries.
-            template<class Type>
-            Type& lookupObjectRef
-            (
-                const word& name,
-                const bool recursive = false
-            ) const;
-
-            //- Lookup and return pointer to the object of the given Type,
-            //  otherwise nullptr if the object was not found,
-            //  or had the incorrect type.
-            //  If recursive, search parent registries.
-            template<class Type>
-            const Type* lookupObjectPtr
-            (
-                const word& name,
-                const bool recursive = false
-            ) const;
-
-
-            //- Lookup and return non-const pointer to the object
-            //  of the given Type,
-            //  otherwise nullptr if the object was not found,
-            //  or had the incorrect type.
-            //  If recursive, search parent registries.
-            template<class Type>
-            Type* lookupObjectRefPtr
-            (
-                const word& name,
-                const bool recursive = false
-            ) const;
-
-
-            //- Return new event number.
-            label getEvent() const;
-
-
-        // Edit
-
-            //- Rename
-            virtual void rename(const word& newName);
-
-            //- Add an regIOobject to registry
-            bool checkIn(regIOobject&) const;
-
-            //- Remove an regIOobject from registry
-            bool checkOut(regIOobject&) const;
-
-
-        // Reading
-
-            //- Return true if any of the object's files have been modified
-            virtual bool modified() const;
-
-            //- Read the objects that have been modified
-            void readModifiedObjects();
-
-            //- Read object if modified
-            virtual bool readIfModified();
-
-
-        // Writing
-
-            //- writeData function required by regIOobject but not used
-            //  for this class, write is used instead
-            virtual bool writeData(Ostream&) const
-            {
-                NotImplemented;
-
-                return false;
-            }
-
-            //- Write the objects
-            virtual bool writeObject
-            (
-                IOstream::streamFormat fmt,
-                IOstream::versionNumber ver,
-                IOstream::compressionType cmp
-            ) const;
+      // Access
+
+        //- Return time
+        const Time& time() const
+        {
+            return time_;
+        }
+
+        //- Return the parent objectRegistry
+        const objectRegistry& parent() const
+        {
+            return parent_;
+        }
+
+        //- Local directory path of this objectRegistry relative to the time
+        virtual const fileName& dbDir() const
+        {
+            return dbDir_;
+        }
+
+
+      // Summary of classes
+
+        //- A summary hash of classes used and their associated object names.
+        //  Behaviour and usage as per IOobjectList::classes
+        HashTable<wordHashSet> classes() const;
+
+        //- A summary hash of classes used and their associated object names
+        //  restricted to objects with names that satisfy the input matcher
+        HashTable<wordHashSet> classes(const wordRe& matcher) const;
+
+        //- A summary hash of classes used and their associated object names
+        //  restricted to objects with names that satisfy the input matcher
+        HashTable<wordHashSet> classes(const wordRes& matcher) const;
+
+
+      // Summary of names
+
+        //- A list of names of the objects
+        wordList names() const;
+
+        //- The names of objects with the given class name
+        wordList names(const word& clsName) const;
+
+        //- The names of objects with the given type
+        template<class Type>
+        wordList names() const;
+
+        //- The names of objects with the given type that also
+        //  have a name satisfying the input matcher
+        template<class Type>
+        wordList names(const wordRe& matcher) const;
+
+        //- The names of objects with the given type that also
+        //  have a name satisfying the input matcher
+        template<class Type>
+        wordList names(const wordRes& matcher) const;
+
+
+      // Summary of names (sorted)
+
+        //- A sorted list of names of the objects
+        wordList sortedNames() const;
+
+        //- The sorted names of objects with the given class name
+        wordList sortedNames(const word& clsName) const;
+
+        //- The sorted names of objects with the given type
+        template<class Type>
+        wordList sortedNames() const;
+
+        //- The sorted names of objects with the given type that also
+        //  have a name satisfying the input matcher
+        template<class Type>
+        wordList sortedNames(const wordRe& matcher) const;
+
+        //- The sorted names of objects with the given type that also
+        //  have a name satisfying the input matcher
+        template<class Type>
+        wordList sortedNames(const wordRes& matcher) const;
+
+
+      // Lookup
+
+        //- Lookup and return a const sub-objectRegistry.
+        //  Optionally create it if it does not exist.
+        //  If recursive, search parent registries.
+        const objectRegistry& subRegistry
+        (
+            const word& name,
+            const bool forceCreate = false,
+            const bool recursive = false
+        ) const;
+
+
+        //- Lookup and return all objects of the given Type
+        template<class Type>
+        HashTable<const Type*> lookupClass(const bool strict = false) const;
+
+        //- Lookup and return all objects of the given Type
+        template<class Type>
+        HashTable<Type*> lookupClass(const bool strict = false);
+
+        //- Is the named Type found?
+        //  If recursive, search parent registries.
+        template<class Type>
+        bool foundObject
+        (
+            const word& name,
+            const bool recursive = false
+        ) const;
+
+        //- Lookup and return the object of the given Type.
+        //  If recursive, search parent registries.
+        template<class Type>
+        const Type& lookupObject
+        (
+            const word& name,
+            const bool recursive = false
+        ) const;
+
+        //- Lookup and return the object of the given Type.
+        //  If recursive, search parent registries.
+        template<class Type>
+        Type& lookupObjectRef
+        (
+            const word& name,
+            const bool recursive = false
+        ) const;
+
+        //- Lookup and return pointer to the object of the given Type,
+        //  otherwise nullptr if the object was not found,
+        //  or had the incorrect type.
+        //  If recursive, search parent registries.
+        template<class Type>
+        const Type* lookupObjectPtr
+        (
+            const word& name,
+            const bool recursive = false
+        ) const;
+
+
+        //- Lookup and return non-const pointer to the object
+        //  of the given Type,
+        //  otherwise nullptr if the object was not found,
+        //  or had the incorrect type.
+        //  If recursive, search parent registries.
+        template<class Type>
+        Type* lookupObjectRefPtr
+        (
+            const word& name,
+            const bool recursive = false
+        ) const;
+
+
+      // Events
+
+        //- Return new event number.
+        label getEvent() const;
+
+
+      // Edit
+
+        //- Rename
+        virtual void rename(const word& newName);
+
+        //- Add an regIOobject to registry
+        bool checkIn(regIOobject& io) const;
+
+        //- Remove an regIOobject from registry
+        bool checkOut(regIOobject& io) const;
+
+
+      // Reading
+
+        //- Return true if any of the object's files have been modified
+        virtual bool modified() const;
+
+        //- Read the objects that have been modified
+        void readModifiedObjects();
+
+        //- Read object if modified
+        virtual bool readIfModified();
+
+
+      // Writing
+
+        //- writeData function required by regIOobject but not used
+        //  for this class, write is used instead
+        virtual bool writeData(Ostream&) const
+        {
+            NotImplemented;
+
+            return false;
+        }
+
+        //- Write the objects
+        virtual bool writeObject
+        (
+            IOstream::streamFormat fmt,
+            IOstream::versionNumber ver,
+            IOstream::compressionType cmp
+        ) const;
 };
 
 
diff --git a/src/OpenFOAM/db/objectRegistry/objectRegistryTemplates.C b/src/OpenFOAM/db/objectRegistry/objectRegistryTemplates.C
index c5c583ad2666e24f3b6f37f5415c79d65e3923a8..040b05f6a3c34ec7ec52ee2e1bd0d1414941d362 100644
--- a/src/OpenFOAM/db/objectRegistry/objectRegistryTemplates.C
+++ b/src/OpenFOAM/db/objectRegistry/objectRegistryTemplates.C
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2011-2015 OpenFOAM Foundation
-     \\/     M anipulation  | Copyright (C) 2016 OpenCFD Ltd.
+     \\/     M anipulation  | Copyright (C) 2016-2017 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -25,95 +25,115 @@ License
 
 #include "objectRegistry.H"
 #include "stringListOps.H"
+#include "predicates.H"
 
-// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
 
-template<class Type>
-Foam::wordList Foam::objectRegistry::names() const
+// Templated implementation for classes()
+template<class UnaryMatchPredicate>
+Foam::HashTable<Foam::wordHashSet> Foam::objectRegistry::classesImpl
+(
+    const objectRegistry& list,
+    const UnaryMatchPredicate& matcher
+)
 {
-    wordList objectNames(size());
+    HashTable<wordHashSet> summary(2*list.size());
 
-    label count=0;
-    forAllConstIter(HashTable<regIOobject*>, *this, iter)
+    // Summary (key,val) = (class-name, object-names)
+    forAllConstIters(list, iter)
     {
-        if (isA<Type>(*iter()))
+        if (matcher(iter.key()))
         {
-            objectNames[count++] = iter()->name();
+            // Create entry (if needed) and insert
+            summary(iter.object()->type()).insert(iter.key());
         }
     }
 
-    objectNames.setSize(count);
-
-    return objectNames;
+    return summary;
 }
 
 
-template<class Type>
-Foam::wordList Foam::objectRegistry::names(const wordRe& matcher) const
+// Templated implementation for names()
+template<class Type, class UnaryMatchPredicate>
+Foam::wordList Foam::objectRegistry::namesImpl
+(
+    const objectRegistry& list,
+    const UnaryMatchPredicate& matcher,
+    const bool doSort
+)
 {
-    wordList objectNames(size());
+    wordList objNames(list.size());
 
     label count = 0;
-    forAllConstIter(HashTable<regIOobject*>, *this, iter)
+    forAllConstIters(list, iter)
     {
-        if (isA<Type>(*iter()))
+        if (isA<Type>(*iter()) && matcher(iter()->name()))
         {
-            const word& objectName = iter()->name();
-
-            if (matcher.match(objectName))
-            {
-                objectNames[count++] = objectName;
-            }
+            objNames[count++] = iter()->name();
         }
     }
 
-    objectNames.setSize(count);
+    objNames.setSize(count);
+
+    if (doSort)
+    {
+        Foam::sort(objNames);
+    }
 
-    return objectNames;
+    return objNames;
 }
 
 
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
 template<class Type>
-Foam::wordList Foam::objectRegistry::names(const wordReList& matcher) const
+Foam::wordList Foam::objectRegistry::names() const
 {
-    wordList names(this->names<Type>());
+    return namesImpl<Type>(*this, predicates::always(), false);
+}
+
 
-    return wordList(names, findStrings(matcher, names));
+template<class Type>
+Foam::wordList Foam::objectRegistry::names(const wordRe& matcher) const
+{
+    return namesImpl<Type>(*this, matcher, false);
 }
 
 
 template<class Type>
-Foam::wordList Foam::objectRegistry::sortedNames() const
+Foam::wordList Foam::objectRegistry::names
+(
+    const wordRes& matcher
+) const
 {
-    wordList sorted(this->names<Type>());
-    sort(sorted);
+    return namesImpl<Type>(*this, matcher, false);
+}
+
 
-    return sorted;
+template<class Type>
+Foam::wordList Foam::objectRegistry::sortedNames() const
+{
+    return namesImpl<Type>(*this, predicates::always(), true);
 }
 
+
 template<class Type>
 Foam::wordList Foam::objectRegistry::sortedNames
 (
-    const wordRe& match
+    const wordRe& matcher
 ) const
 {
-    wordList sorted(this->names<Type>(match));
-    sort(sorted);
-
-    return sorted;
+    return namesImpl<Type>(*this, matcher, true);
 }
 
 
 template<class Type>
 Foam::wordList Foam::objectRegistry::sortedNames
 (
-    const wordReList& matcher
+    const wordRes& matcher
 ) const
 {
-    wordList sorted(this->names<Type>(matcher));
-    sort(sorted);
-
-    return sorted;
+    return namesImpl<Type>(*this, matcher, true);
 }
 
 
@@ -125,7 +145,7 @@ Foam::HashTable<const Type*> Foam::objectRegistry::lookupClass
 {
     HashTable<const Type*> objectsOfClass(size());
 
-    forAllConstIter(HashTable<regIOobject*>, *this, iter)
+    forAllConstIters(*this, iter)
     {
         if (strict ? isType<Type>(*iter()) : isA<Type>(*iter()))
         {
@@ -149,7 +169,7 @@ Foam::HashTable<Type*> Foam::objectRegistry::lookupClass
 {
     HashTable<Type*> objectsOfClass(size());
 
-    forAllIter(HashTable<regIOobject*>, *this, iter)
+    forAllIters(*this, iter)
     {
         if (strict ? isType<Type>(*iter()) : isA<Type>(*iter()))
         {
@@ -194,7 +214,7 @@ const Type& Foam::objectRegistry::lookupObject
 {
     const_iterator iter = find(name);
 
-    if (iter != end())
+    if (iter.found())
     {
         const Type* ptr = dynamic_cast<const Type*>(iter());
 
@@ -252,7 +272,7 @@ const Type* Foam::objectRegistry::lookupObjectPtr
 {
     const_iterator iter = find(name);
 
-    if (iter != end())
+    if (iter.found())
     {
         const Type* ptr = dynamic_cast<const Type*>(iter());
 
diff --git a/src/OpenFOAM/meshes/polyMesh/zones/ZoneMesh/ZoneMesh.C b/src/OpenFOAM/meshes/polyMesh/zones/ZoneMesh/ZoneMesh.C
index 94f1c23a752ba0a07091ecff23b286ecee02dfc6..066c9c268f86493bfb163225a4be24629b5870c3 100644
--- a/src/OpenFOAM/meshes/polyMesh/zones/ZoneMesh/ZoneMesh.C
+++ b/src/OpenFOAM/meshes/polyMesh/zones/ZoneMesh/ZoneMesh.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  | Copyright (C) 2016 OpenCFD Ltd.
+     \\/     M anipulation  | Copyright (C) 2016-2017 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -47,23 +47,23 @@ void Foam::ZoneMesh<ZoneType, MeshType>::calcZoneMap() const
         // Count number of objects in all zones
         label nObjects = 0;
 
-        forAll(*this, zoneI)
+        forAll(*this, zonei)
         {
-            nObjects += this->operator[](zoneI).size();
+            nObjects += this->operator[](zonei).size();
         }
 
         zoneMapPtr_ = new Map<label>(2*nObjects);
         Map<label>& zm = *zoneMapPtr_;
 
-        // Fill in objects of all zones into the map.  The key is the global
-        // object index and the result is the zone index
-        forAll(*this, zoneI)
+        // Fill in objects of all zones into the map.
+        // The key is the global object index, value is the zone index
+        forAll(*this, zonei)
         {
-            const labelList& zoneObjects = this->operator[](zoneI);
+            const labelList& zoneObjects = this->operator[](zonei);
 
             forAll(zoneObjects, objI)
             {
-                zm.insert(zoneObjects[objI], zoneI);
+                zm.insert(zoneObjects[objI], zonei);
             }
         }
     }
@@ -91,27 +91,23 @@ bool Foam::ZoneMesh<ZoneType, MeshType>::read()
         PtrList<entry> patchEntries(is);
         zones.setSize(patchEntries.size());
 
-        forAll(zones, zoneI)
+        forAll(zones, zonei)
         {
             zones.set
             (
-                zoneI,
+                zonei,
                 ZoneType::New
                 (
-                    patchEntries[zoneI].keyword(),
-                    patchEntries[zoneI].dict(),
-                    zoneI,
+                    patchEntries[zonei].keyword(),
+                    patchEntries[zonei].dict(),
+                    zonei,
                     *this
                 )
             );
         }
 
         // Check state of IOstream
-        is.check
-        (
-            "ZoneMesh::ZoneMesh"
-            "(const IOobject&, const MeshType&)"
-        );
+        is.check(FUNCTION_NAME);
 
         close();
 
@@ -125,6 +121,40 @@ bool Foam::ZoneMesh<ZoneType, MeshType>::read()
 }
 
 
+// Templated implementation for names()
+template<class ZoneType, class MeshType>
+template<class UnaryMatchPredicate>
+Foam::wordList Foam::ZoneMesh<ZoneType, MeshType>::namesImpl
+(
+    const PtrList<ZoneType>& zones,
+    const UnaryMatchPredicate& matcher,
+    const bool doSort
+)
+{
+    wordList lst(zones.size());
+
+    label count = 0;
+    forAll(zones, zonei)
+    {
+        const word& zname = zones[zonei].name();
+
+        if (matcher(zname))
+        {
+            lst[count++] = zname;
+        }
+    }
+
+    lst.setSize(count);
+
+    if (doSort)
+    {
+        Foam::sort(lst);
+    }
+
+    return lst;
+}
+
+
 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
 
 template<class ZoneType, class MeshType>
@@ -179,9 +209,9 @@ Foam::ZoneMesh<ZoneType, MeshType>::ZoneMesh
         // Nothing read. Use supplied zones
         PtrList<ZoneType>& zones = *this;
         zones.setSize(pzm.size());
-        forAll(zones, zoneI)
+        forAll(zones, zonei)
         {
-            zones.set(zoneI, pzm[zoneI].clone(*this).ptr());
+            zones.set(zonei, pzm[zonei].clone(*this).ptr());
         }
     }
 }
@@ -238,9 +268,9 @@ Foam::wordList Foam::ZoneMesh<ZoneType, MeshType>::types() const
 
     wordList lst(zones.size());
 
-    forAll(zones, zoneI)
+    forAll(zones, zonei)
     {
-        lst[zoneI] = zones[zoneI].type();
+        lst[zonei] = zones[zonei].type();
     }
 
     return lst;
@@ -254,9 +284,9 @@ Foam::wordList Foam::ZoneMesh<ZoneType, MeshType>::names() const
 
     wordList lst(zones.size());
 
-    forAll(zones, zoneI)
+    forAll(zones, zonei)
     {
-        lst[zoneI] = zones[zoneI].name();
+        lst[zonei] = zones[zonei].name();
     }
 
     return lst;
@@ -269,22 +299,18 @@ Foam::wordList Foam::ZoneMesh<ZoneType, MeshType>::names
     const wordRe& matcher
 ) const
 {
-    wordList lst = this->names();
-
-    return wordList(lst, findStrings(matcher, lst));
+    return namesImpl(*this, matcher, false);
 }
 
 
 template<class ZoneType, class MeshType>
 Foam::wordList Foam::ZoneMesh<ZoneType, MeshType>::names
 (
-    const wordReList& matcher
+    const wordRes& matcher
 )
 const
 {
-    wordList lst = this->names();
-
-    return wordList(lst, findStrings(matcher, lst));
+    return namesImpl(*this, matcher, false);
 }
 
 
@@ -304,24 +330,18 @@ Foam::wordList Foam::ZoneMesh<ZoneType, MeshType>::sortedNames
     const wordRe& matcher
 ) const
 {
-    wordList sortedLst = this->names(matcher);
-    sort(sortedLst);
-
-    return sortedLst;
+    return namesImpl(*this, matcher, true);
 }
 
 
 template<class ZoneType, class MeshType>
 Foam::wordList Foam::ZoneMesh<ZoneType, MeshType>::sortedNames
 (
-    const wordReList& matcher
+    const wordRes& matcher
 )
 const
 {
-    wordList sortedLst = this->names(matcher);
-    sort(sortedLst);
-
-    return sortedLst;
+    return namesImpl(*this, matcher, true);
 }
 
 
@@ -342,15 +362,15 @@ Foam::labelList Foam::ZoneMesh<ZoneType, MeshType>::findIndices
         else
         {
             indices.setSize(this->size());
-            label nFound = 0;
+            label count = 0;
             forAll(*this, i)
             {
                 if (key == operator[](i).name())
                 {
-                    indices[nFound++] = i;
+                    indices[count++] = i;
                 }
             }
-            indices.setSize(nFound);
+            indices.setSize(count);
         }
     }
 
@@ -388,7 +408,7 @@ Foam::label Foam::ZoneMesh<ZoneType, MeshType>::findIndex
         }
     }
 
-    // not found
+    // Not found
     return -1;
 }
 
@@ -401,11 +421,11 @@ Foam::label Foam::ZoneMesh<ZoneType, MeshType>::findZoneID
 {
     const PtrList<ZoneType>& zones = *this;
 
-    forAll(zones, zoneI)
+    forAll(zones, zonei)
     {
-        if (zones[zoneI].name() == zoneName)
+        if (zones[zonei].name() == zoneName)
         {
-            return zoneI;
+            return zonei;
         }
     }
 
@@ -417,7 +437,7 @@ Foam::label Foam::ZoneMesh<ZoneType, MeshType>::findZoneID
             << "List of available zone names: " << names() << endl;
     }
 
-    // not found
+    // Not found
     return -1;
 }
 
@@ -447,9 +467,9 @@ void Foam::ZoneMesh<ZoneType, MeshType>::clearAddressing()
 
     PtrList<ZoneType>& zones = *this;
 
-    forAll(zones, zoneI)
+    forAll(zones, zonei)
     {
-        zones[zoneI].clearAddressing();
+        zones[zonei].clearAddressing();
     }
 }
 
@@ -472,9 +492,9 @@ bool Foam::ZoneMesh<ZoneType, MeshType>::checkDefinition
 
     const PtrList<ZoneType>& zones = *this;
 
-    forAll(zones, zoneI)
+    forAll(zones, zonei)
     {
-        inError |= zones[zoneI].checkDefinition(report);
+        inError |= zones[zonei].checkDefinition(report);
     }
     return inError;
 }
@@ -535,16 +555,16 @@ bool Foam::ZoneMesh<ZoneType, MeshType>::checkParallelSync
     // Check contents
     if (!hasError)
     {
-        forAll(zones, zoneI)
+        forAll(zones, zonei)
         {
-            if (zones[zoneI].checkParallelSync(false))
+            if (zones[zonei].checkParallelSync(false))
             {
                 hasError = true;
 
                 if (debug || (report && Pstream::master()))
                 {
-                    Info<< " ***Zone " << zones[zoneI].name()
-                        << " of type " << zones[zoneI].type()
+                    Info<< " ***Zone " << zones[zonei].name()
+                        << " of type " << zones[zonei].type()
                         << " is not correctly synchronised"
                         << " across coupled boundaries."
                         << " (coupled faces are either not both"
@@ -563,9 +583,9 @@ void Foam::ZoneMesh<ZoneType, MeshType>::movePoints(const pointField& p)
 {
     PtrList<ZoneType>& zones = *this;
 
-    forAll(zones, zoneI)
+    forAll(zones, zonei)
     {
-        zones[zoneI].movePoints(p);
+        zones[zonei].movePoints(p);
     }
 }
 
@@ -586,9 +606,9 @@ const ZoneType& Foam::ZoneMesh<ZoneType, MeshType>::operator[]
     const word& zoneName
 ) const
 {
-    const label zoneI = findZoneID(zoneName);
+    const label zonei = findZoneID(zoneName);
 
-    if (zoneI < 0)
+    if (zonei < 0)
     {
         FatalErrorInFunction
             << "Zone named " << zoneName << " not found." << nl
@@ -596,7 +616,7 @@ const ZoneType& Foam::ZoneMesh<ZoneType, MeshType>::operator[]
             << abort(FatalError);
     }
 
-    return operator[](zoneI);
+    return operator[](zonei);
 }
 
 
@@ -606,9 +626,9 @@ ZoneType& Foam::ZoneMesh<ZoneType, MeshType>::operator[]
     const word& zoneName
 )
 {
-    const label zoneI = findZoneID(zoneName);
+    const label zonei = findZoneID(zoneName);
 
-    if (zoneI < 0)
+    if (zonei < 0)
     {
         FatalErrorInFunction
             << "Zone named " << zoneName << " not found." << nl
@@ -616,7 +636,7 @@ ZoneType& Foam::ZoneMesh<ZoneType, MeshType>::operator[]
             << abort(FatalError);
     }
 
-    return operator[](zoneI);
+    return operator[](zonei);
 }
 
 
@@ -631,9 +651,9 @@ Foam::Ostream& Foam::operator<<
 {
     os  << zones.size() << nl << token::BEGIN_LIST;
 
-    forAll(zones, zoneI)
+    forAll(zones, zonei)
     {
-        zones[zoneI].writeDict(os);
+        zones[zonei].writeDict(os);
     }
 
     os  << token::END_LIST;
diff --git a/src/OpenFOAM/meshes/polyMesh/zones/ZoneMesh/ZoneMesh.H b/src/OpenFOAM/meshes/polyMesh/zones/ZoneMesh/ZoneMesh.H
index 7d79a37a1e8237bccf670c24cd8decec59665142..d76823b85222ea5bd57b5abb494a40bbc75e6f11 100644
--- a/src/OpenFOAM/meshes/polyMesh/zones/ZoneMesh/ZoneMesh.H
+++ b/src/OpenFOAM/meshes/polyMesh/zones/ZoneMesh/ZoneMesh.H
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
-     \\/     M anipulation  | Copyright (C) 2016 OpenCFD Ltd.
+     \\/     M anipulation  | Copyright (C) 2016-2017 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -40,7 +40,7 @@ SourceFiles
 #include "pointField.H"
 #include "Map.H"
 #include "PackedBoolList.H"
-#include "wordReList.H"
+#include "wordRes.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
@@ -54,7 +54,7 @@ namespace Foam
 template<class ZoneType, class MeshType> class ZoneMesh;
 
 template<class ZoneType, class MeshType>
-Ostream& operator<<(Ostream&, const ZoneMesh<ZoneType, MeshType>&);
+Ostream& operator<<(Ostream& os, const ZoneMesh<ZoneType, MeshType>& zones);
 
 /*---------------------------------------------------------------------------*\
                            Class ZoneMesh Declaration
@@ -80,6 +80,19 @@ class ZoneMesh
         //- Read if IOobject flags set. Return true if read.
         bool read();
 
+        //- Create zone map
+        void calcZoneMap() const;
+
+        //- Templated implementation for names()
+        template<class UnaryMatchPredicate>
+        static wordList namesImpl
+        (
+            const PtrList<ZoneType>& zones,
+            const UnaryMatchPredicate& matcher,
+            const bool doSort
+        );
+
+
         //- Disallow construct as copy
         ZoneMesh(const ZoneMesh&) = delete;
 
@@ -87,10 +100,6 @@ class ZoneMesh
         void operator=(const ZoneMesh<ZoneType, MeshType>&) = delete;
 
 
-        //- Create zone map
-        void calcZoneMap() const;
-
-
 public:
 
     // Constructors
@@ -98,24 +107,24 @@ public:
         //- Read constructor given IOobject and a MeshType reference
         ZoneMesh
         (
-            const IOobject&,
-            const MeshType&
+            const IOobject& io,
+            const MeshType& mesh
         );
 
         //- Construct given size
         ZoneMesh
         (
-            const IOobject&,
-            const MeshType&,
+            const IOobject& io,
+            const MeshType& mesh,
             const label size
         );
 
-         //- Construct given a PtrList
+        //- Construct given a PtrList
         ZoneMesh
         (
-            const IOobject&,
-            const MeshType&,
-            const PtrList<ZoneType>&
+            const IOobject& io,
+            const MeshType& mesh,
+            const PtrList<ZoneType>& pzm
         );
 
 
@@ -146,32 +155,32 @@ public:
         wordList names() const;
 
         //- A list of the zone names satisfying the input matcher
-        wordList names(const wordRe&) const;
+        wordList names(const wordRe& matcher) const;
 
         //- A list of the zone names satisfying the input matchers
-        wordList names(const wordReList&) const;
+        wordList names(const wordRes& matcher) const;
 
         //- Sorted list of the zone names
         wordList sortedNames() const;
 
         //- Sorted list of the zone names satisfying the input matcher
-        wordList sortedNames(const wordRe&) const;
+        wordList sortedNames(const wordRe& matcher) const;
 
         //- Sorted list of the zone names satisfying the input matchers
-        wordList sortedNames(const wordReList&) const;
+        wordList sortedNames(const wordRes& matcher) const;
 
 
         //- Return zone indices for all matches
-        labelList findIndices(const keyType&) const;
+        labelList findIndices(const keyType& key) const;
 
         //- Return zone index for the first match, return -1 if not found
-        label findIndex(const keyType&) const;
+        label findIndex(const keyType& key) const;
 
         //- Find zone index given a name
         label findZoneID(const word& zoneName) const;
 
         //- Mark cells that match the zone specification
-        PackedBoolList findMatching(const keyType&) const;
+        PackedBoolList findMatching(const keyType& key) const;
 
         //- Clear addressing
         void clearAddressing();
@@ -187,10 +196,10 @@ public:
         bool checkParallelSync(const bool report = false) const;
 
         //- Correct zone mesh after moving points
-        void movePoints(const pointField&);
+        void movePoints(const pointField& p);
 
         //- writeData member function required by regIOobject
-        bool writeData(Ostream&) const;
+        bool writeData(Ostream& os) const;
 
     // Member Operators
 
@@ -198,18 +207,18 @@ public:
         using PtrList<ZoneType>::operator[];
 
         //- Return const reference to ZoneType by name.
-        const ZoneType& operator[](const word&) const;
+        const ZoneType& operator[](const word& zoneName) const;
 
         //- Return reference to ZoneType by name.
-        ZoneType& operator[](const word&);
+        ZoneType& operator[](const word& zoneName);
 
 
     // Ostream operator
 
         friend Ostream& operator<< <ZoneType, MeshType>
         (
-            Ostream&,
-            const ZoneMesh<ZoneType, MeshType>&
+            Ostream& os,
+            const ZoneMesh<ZoneType, MeshType>& zones
         );
 };