diff --git a/applications/test/IOobjectList/Test-IOobjectList.C b/applications/test/IOobjectList/Test-IOobjectList.C
index ec7ce76299f17dfb26db64063d74926e625422d6..3e0850c0d7336bfcaf62dfe5a4f1c9b39cebaedf 100644
--- a/applications/test/IOobjectList/Test-IOobjectList.C
+++ b/applications/test/IOobjectList/Test-IOobjectList.C
@@ -32,6 +32,8 @@ Description
 #include "timeSelector.H"
 #include "IOobjectList.H"
 #include "hashedWordList.H"
+#include "labelIOList.H"
+#include "scalarIOList.H"
 
 using namespace Foam;
 
@@ -80,6 +82,67 @@ void reportDetail(const IOobjectList& objects)
 }
 
 
+template<class Type>
+void filterTest(const IOobjectList& objs, const wordRe& re)
+{
+    Info<< "Filter = " << re << nl;
+
+    const word& typeName = Type::typeName;
+
+    Info<< "    <" << typeName <<">(" << re << ") : "
+        << objs.count<Type>(re) << nl
+        << "    (" << typeName << "::typeName, " << re << ") : "
+        << objs.count(typeName, re) << nl;
+
+    Info<< "    <" << typeName << ">(" << re << ") : "
+        << flatOutput(objs.sortedNames<Type>(re)) << nl
+        // << flatOutput(objs.names<Type>(re)) << nl
+        << "    (" << typeName << "::typeName, " << re << ") : "
+        << flatOutput(objs.sortedNames(typeName, re)) << nl
+        //<< flatOutput(objs.names(typeName, re)) << nl
+        ;
+
+
+    wordRe reClass("vol.*Field", wordRe::REGEX);
+    wordRe re2(re, wordRe::REGEX_ICASE);
+
+    Info<< "General" << nl
+        << "    <void>(" << re << ") : "
+        << flatOutput(objs.sortedNames<void>(re)) << nl
+        << "    (" << reClass << ", " << re2 <<" ignore-case) : "
+        << flatOutput(objs.sortedNames(reClass, re2)) << nl
+        ;
+
+    Info<< nl;
+}
+
+
+void registryTests(const IOobjectList& objs)
+{
+    Info<< nl << "IOobjectList " << flatOutput(objs.sortedNames()) << nl;
+
+    Info<< "count" << nl
+        << "    <void>()    : " << objs.count<void>() << nl
+        << "    <labelList>()   : " << objs.count<labelIOList>() << nl
+        << "    <scalarList>()   : " << objs.count<scalarIOList>() << nl
+        << nl;
+    Info<< "    <volScalarField>()    : "
+        << objs.count<volScalarField>() << nl
+        << "    (volScalarField::typeName) : "
+        << objs.count(volScalarField::typeName) << nl;
+    Info<< "    <volVectorField>()    : "
+        << objs.count<volVectorField>() << nl
+        << "    (volVectorField::typeName) : "
+        << objs.count(volVectorField::typeName) << nl;
+
+
+    Info<< nl << "Filter on names:" << nl;
+    filterTest<volScalarField>(objs, wordRe("[p-z].*", wordRe::DETECT));
+
+    Info<< nl;
+}
+
+
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 // Main program:
 
@@ -165,6 +228,8 @@ int main(int argc, char *argv[])
         Info<<"remove: " << flatOutput(subsetTypes) << nl;
         Info<<"Pruned: " << classes << nl;
 
+        registryTests(objects);
+
         // On last time
         if (timeI == timeDirs.size()-1)
         {
diff --git a/applications/test/objectRegistry/Test-objectRegistry.C b/applications/test/objectRegistry/Test-objectRegistry.C
index 73e9f193d392cfdbe31a37dbb2e95c67e3bbec99..ba56f115be6743a726c9bc9a9b7a4491bc87f243 100644
--- a/applications/test/objectRegistry/Test-objectRegistry.C
+++ b/applications/test/objectRegistry/Test-objectRegistry.C
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2016 OpenCFD Ltd.
+    \\  /    A nd           | Copyright (C) 2016-2018 OpenCFD Ltd.
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -34,8 +34,8 @@ Description
 #include "Time.H"
 #include "polyMesh.H"
 #include "IOstreams.H"
+#include "FlatOutput.H"
 #include "objectRegistry.H"
-#include "hashedWordList.H"
 
 using namespace Foam;
 
@@ -45,22 +45,6 @@ using namespace Foam;
 bool recursive = false;
 
 
-template<class Type>
-Foam::Ostream& printList(Foam::Ostream& os, const UList<Type>& list)
-{
-    // list with out any linebreaks
-    os  << '(';
-    forAll(list, i)
-    {
-        if (i) os << ' ';
-        os  << list[i];
-    }
-    os  << ')';
-
-    return os;
-}
-
-
 void printRegistry
 (
     Foam::Ostream& os,
@@ -76,8 +60,8 @@ void printRegistry
     Foam::label indent
 )
 {
-    wordList names = obr.sortedNames();
-    hashedWordList regs = obr.sortedNames<objectRegistry>();
+    wordList names(obr.sortedNames());
+    wordList regs(obr.sortedNames<objectRegistry>());
 
     std::string prefix;
     for (label i=indent; i; --i)
@@ -88,23 +72,13 @@ void printRegistry
     os  << '#' << prefix.c_str() << obr.name()
         << " parent:" << obr.parent().name() << nl;
 
-    // all names
-    {
-        os  << ' ' << prefix.c_str() << "objects: ";
-        printList(os, names) << nl;
-    }
+    os  << ' ' << prefix.c_str() << "objects: " << flatOutput(names) << nl;
+    os  << ' ' << prefix.c_str() << "registries: " << flatOutput(regs) << nl;
 
-    // sub-registry names
-    {
-        os  << ' ' << prefix.c_str() << "registries: ";
-        printList(os, regs) << nl;
-    }
 
     // Print, but skip expansion of sub-registries for now
-    forAll(names, i)
+    for (const word& name : names)
     {
-        const word& name = names[i];
-
         os  << (regs.found(name) ? '-' : ' ')
             << prefix.c_str() << name << " => " << obr[name]->type() << nl;
     }
@@ -115,9 +89,8 @@ void printRegistry
     os  << '\n';
 
     // Now descend into the sub-registries
-    forAll(regs, i)
+    for (const word& name : regs)
     {
-        const word& name = regs[i];
         const objectRegistry& next = obr.lookupObject<objectRegistry>
         (
             name,
@@ -240,8 +213,8 @@ int main(int argc, char *argv[])
         );
     }
 
-    Info<< "after adding some entries, top-level now contains: ";
-    printList(Info, db.names()) << endl;
+    Info<< "after adding some entries, top-level now contains: "
+        << flatOutput(db.names()) << endl;
 
     Info<<"## Now attempt to add a few more entries ##" << nl;
 
diff --git a/applications/test/objectRegistry2/Make/files b/applications/test/objectRegistry2/Make/files
new file mode 100644
index 0000000000000000000000000000000000000000..208771853c25a1483c3222f71cd5639587c9247f
--- /dev/null
+++ b/applications/test/objectRegistry2/Make/files
@@ -0,0 +1,3 @@
+Test-objectRegistry2.C
+
+EXE = $(FOAM_USER_APPBIN)/Test-objectRegistry2
diff --git a/applications/test/objectRegistry2/Make/options b/applications/test/objectRegistry2/Make/options
new file mode 100644
index 0000000000000000000000000000000000000000..969020c4afaf5d784299462b9e1af282040ba6b4
--- /dev/null
+++ b/applications/test/objectRegistry2/Make/options
@@ -0,0 +1,8 @@
+EXE_INC = \
+    -I$(LIB_SRC)/finiteVolume/lnInclude \
+    -I$(LIB_SRC)/meshTools/lnInclude
+
+EXE_LIBS = \
+    -lfiniteVolume \
+    -lmeshTools \
+    -lgenericPatchFields
diff --git a/applications/test/objectRegistry2/Test-objectRegistry2.C b/applications/test/objectRegistry2/Test-objectRegistry2.C
new file mode 100644
index 0000000000000000000000000000000000000000..eab159ccfc28deecff5009d2e046047fc0ed49b7
--- /dev/null
+++ b/applications/test/objectRegistry2/Test-objectRegistry2.C
@@ -0,0 +1,307 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2018 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/>.
+
+Application
+    Test-objectRegistry2
+
+Description
+    Print objectRegistry information, with some additional tests.
+
+\*---------------------------------------------------------------------------*/
+
+#include "argList.H"
+#include "Time.H"
+#include "fvCFD.H"
+#include "fvMesh.H"
+#include "volFields.H"
+#include "IOobjectList.H"
+#include "timeSelector.H"
+#include "ReadFields.H"
+#include "IOstreams.H"
+
+using namespace Foam;
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+template<class Type>
+bool loadField(fvMesh& mesh, const word& fieldName)
+{
+    typedef GeometricField<Type, fvPatchField, volMesh> VolFieldType;
+    typedef GeometricField<Type, fvsPatchField, surfaceMesh> SurfaceFieldType;
+
+    if (mesh.objectRegistry::found(fieldName))
+    {
+        // Info<< fieldName << " already in database" << endl;
+        return false;
+    }
+
+    IOobject fieldHeader
+    (
+        fieldName,
+        mesh.time().timeName(),
+        mesh,
+        IOobject::MUST_READ,
+        IOobject::NO_WRITE
+    );
+
+    if (fieldHeader.typeHeaderOk<VolFieldType>(true, true, false))
+    {
+        // Store field on mesh database
+        VolFieldType* ptr = new VolFieldType(fieldHeader, mesh);
+        mesh.objectRegistry::store(ptr);
+        return true;
+    }
+    else if (fieldHeader.typeHeaderOk<SurfaceFieldType>(true, true, false))
+    {
+        // Store field on mesh database
+        SurfaceFieldType* ptr = new SurfaceFieldType(fieldHeader, mesh);
+        mesh.objectRegistry::store(ptr);
+        return true;
+    }
+
+    return false;
+}
+
+
+bool loadField(fvMesh& mesh, const word& fieldName)
+{
+    return
+    (
+        !mesh.objectRegistry::found(fieldName)
+    &&
+        (
+            loadField<scalar>(mesh, fieldName)
+         || loadField<vector>(mesh, fieldName)
+         || loadField<sphericalTensor>(mesh, fieldName)
+         || loadField<symmTensor>(mesh, fieldName)
+         || loadField<tensor>(mesh, fieldName)
+        )
+    );
+}
+
+
+void loadFields(fvMesh& mesh, const IOobjectList& objects)
+{
+    for (const word& fieldName : objects.names())
+    {
+        loadField(mesh, fieldName);
+    }
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+void printRegistry
+(
+    Foam::Ostream& os,
+    const Foam::objectRegistry& obr,
+    Foam::label indent = 4
+);
+
+
+void printRegistry
+(
+    Foam::Ostream& os,
+    const Foam::objectRegistry& obr,
+    Foam::label indent
+)
+{
+    wordList names(obr.sortedNames());
+    wordList regs(obr.sortedNames<objectRegistry>());
+
+    std::string prefix;
+    for (label i=indent; i; --i)
+    {
+        prefix += ' ';
+    }
+
+    os  << '#' << prefix.c_str() << obr.name()
+        << " parent:" << obr.parent().name() << nl;
+
+    os  << ' ' << prefix.c_str() << "objects: " << flatOutput(names) << nl;
+    os  << ' ' << prefix.c_str() << "registries: " << flatOutput(regs) << nl;
+
+
+    // Print, but skip expansion of sub-registries for now
+    for (const word& name : names)
+    {
+        os  << (regs.found(name) ? '-' : ' ')
+            << prefix.c_str() << name << " => " << obr[name]->type() << nl;
+    }
+    for (label i=indent; i; --i)
+    {
+        os  << '-'; // divider
+    }
+    os  << '\n';
+
+    // Now descend into the sub-registries
+    for (const word& name : regs)
+    {
+        const objectRegistry& next = obr.lookupObject<objectRegistry>
+        (
+            name,
+            false // non-recursive
+        );
+
+        os  << prefix.c_str()
+            << "current:" << obr.name() << " next:"
+            << next.name() << " next-parent:" << next.parent().name() << nl;
+
+        os  << prefix.c_str() << name << " => " << obr[name]->type();
+
+        if ("dictionary" == obr[name]->type())
+        {
+            os  << " (skip dictionary)" << nl;
+        }
+        else
+        {
+            os  << nl;
+            printRegistry(os, next, indent + 4);
+        }
+    }
+}
+
+
+template<class Type>
+void filterTest(const objectRegistry& obr, const wordRe& re)
+{
+    Info<< nl << "Filter on names:" << nl;
+
+    Info<< "Filter = " << re << nl;
+
+    const word& typeName = Type::typeName;
+
+    Info<< "    <" << typeName <<">(" << re << ") : "
+        << obr.count<Type>(re) << nl
+        << "    (" << typeName << "::typeName, " << re << ") : "
+        << obr.count(typeName, re) << nl;
+
+    Info<< "    <" << typeName << ">(" << re << ") : "
+        << flatOutput(obr.sortedNames<Type>(re)) << nl
+        // << flatOutput(obr.names<Type>(re)) << nl
+        << "    (" << typeName << "::typeName, " << re << ") : "
+        << flatOutput(obr.sortedNames(typeName, re)) << nl
+        //<< flatOutput(obr.names(typeName, re)) << nl
+        ;
+
+
+    wordRe reClass("vol.*Field", wordRe::REGEX);
+    wordRe re2(re, wordRe::REGEX_ICASE);
+
+    Info<< "General" << nl
+        << "    <void>(" << re << ") : "
+        << flatOutput(obr.sortedNames<void>(re)) << nl
+        << "    (" << reClass << ", " << re2 <<" ignore-case) : "
+        << flatOutput(obr.sortedNames(reClass, re2)) << nl
+        ;
+
+    Info<< nl;
+}
+
+
+void registryTests(const objectRegistry& obr)
+{
+    Info<< nl << "Registry: " << obr.name() << nl
+        << " names: " << flatOutput(obr.sortedNames()) << nl;
+
+    Info<< "count" << nl
+        << "    <void>()    : " << obr.count<void>() << nl
+        << "    <labelList>()   : " << obr.count<labelList>() << nl
+        << "    <labelList>(strict) : " << obr.count<labelList>(true) << nl
+        << "    <scalarList>()   : " << obr.count<scalarList>() << nl
+        << "    <scalarList>(strict) : " << obr.count<scalarList>(true) << nl;
+    Info<< "    <volScalarField>()    : "
+        << obr.count<volScalarField>() << nl
+        << "    (volScalarField::typeName) : "
+        << obr.count(volScalarField::typeName) << nl;
+    Info<< "    <volVectorField>()    : "
+        << obr.count<volVectorField>() << nl
+        << "    (volVectorField::typeName) : "
+        << obr.count(volVectorField::typeName) << nl;
+
+    Info<< nl << "Filter on names:" << nl;
+
+    filterTest<volScalarField>(obr, wordRe("[p-z].*", wordRe::DETECT));
+
+    Info<< nl;
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+//  Main program:
+
+int main(int argc, char *argv[])
+{
+    argList::noBanner();
+    argList::noParallel();
+//    argList::addOption
+//    (
+//        "filter",
+//        "wordRes",
+//        "filter keys with names or regexs"
+//    );
+
+    // timeSelector::addOptions();
+    timeSelector::addOptions(true, true);
+
+    #include "setRootCase.H"
+
+//    wordRes matcher;
+//    if (args.readListIfPresent<wordRe>("filter", matcher))
+//    {
+//        Info<<"limit names: " << matcher << nl;
+//    }
+
+    #include "createTime.H"
+    #include "createMesh.H"
+
+    instantList timeDirs = timeSelector::select0(runTime, args);
+
+    forAll(timeDirs, timeI)
+    {
+        runTime.setTime(timeDirs[timeI], timeI);
+
+        Info<< "Time: " << runTime.timeName() << endl;
+
+        // Read objects in time directory
+        IOobjectList objects(mesh, runTime.timeName());
+
+        // Read volFields
+        loadFields(mesh, objects);
+
+        printRegistry(Info, mesh);
+
+        registryTests(mesh);
+
+        Info<< nl;
+    }
+
+
+    Info<<"\nEnd\n" << endl;
+
+    return 0;
+}
+
+
+// ************************************************************************* //
diff --git a/src/OpenFOAM/db/IOobjectList/IOobjectList.C b/src/OpenFOAM/db/IOobjectList/IOobjectList.C
index 95f84c49c1a19b27964f2c50c5189977b6fbe5e4..8d914a1b470f49c32fe6ae0a9a13214b2bb5805f 100644
--- a/src/OpenFOAM/db/IOobjectList/IOobjectList.C
+++ b/src/OpenFOAM/db/IOobjectList/IOobjectList.C
@@ -33,7 +33,8 @@ License
 
 bool Foam::IOobjectList::checkNames(wordList& masterNames, const bool syncPar)
 {
-    // Sort for consistent order on all processors
+    // Sort for consistent order on all processors.
+    // Even do this for serial runs, for consistent behaviour
     Foam::sort(masterNames);
 
     if (syncPar && Pstream::parRun())
@@ -273,6 +274,13 @@ Foam::HashTable<Foam::wordHashSet> Foam::IOobjectList::classes() const
 }
 
 
+Foam::label Foam::IOobjectList::count(const char* clsName) const
+{
+    // No nullptr check - only called with string literals
+    return count(static_cast<word>(clsName));
+}
+
+
 Foam::wordList Foam::IOobjectList::names() const
 {
     return HashPtrTable<IOobject>::toc();
@@ -288,37 +296,33 @@ Foam::wordList Foam::IOobjectList::names(const bool syncPar) const
 }
 
 
-Foam::wordList Foam::IOobjectList::names
-(
-    const word& clsName
-) const
+Foam::wordList Foam::IOobjectList::names(const char* clsName) const
 {
-    // sort/sync: false, false
-    return namesImpl(*this, clsName, predicates::always(), false, false);
+    // No nullptr check - only called with string literals
+    return names(static_cast<word>(clsName));
 }
 
 
 Foam::wordList Foam::IOobjectList::names
 (
-    const word& clsName,
+    const char* clsName,
     const bool syncPar
 ) const
 {
-    // sort: false
-    return namesImpl(*this, clsName, predicates::always(), false, syncPar);
+    // No nullptr check - only called with string literals
+    return names(static_cast<word>(clsName), syncPar);
 }
 
 
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
 Foam::wordList Foam::IOobjectList::sortedNames() const
 {
     return HashPtrTable<IOobject>::sortedToc();
 }
 
 
-Foam::wordList Foam::IOobjectList::sortedNames
-(
-    const bool syncPar
-) const
+Foam::wordList Foam::IOobjectList::sortedNames(const bool syncPar) const
 {
     wordList objNames(HashPtrTable<IOobject>::sortedToc());
 
@@ -327,24 +331,56 @@ Foam::wordList Foam::IOobjectList::sortedNames
 }
 
 
-Foam::wordList Foam::IOobjectList::sortedNames
-(
-    const word& clsName
-) const
+Foam::wordList Foam::IOobjectList::sortedNames(const char* clsName) const
 {
-    // sort/sync: true, false
-    return namesImpl(*this, clsName, predicates::always(), true, false);
+    // No nullptr check - only called with string literals
+    return sortedNames(static_cast<word>(clsName));
 }
 
 
 Foam::wordList Foam::IOobjectList::sortedNames
 (
-    const word& clsName,
+    const char* clsName,
     const bool syncPar
 ) const
 {
-    // sort: true
-    return namesImpl(*this, clsName, predicates::always(), true, syncPar);
+    // No nullptr check - only called with string literals
+    return names(static_cast<word>(clsName), syncPar);
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+Foam::label Foam::IOobjectList::prune_0()
+{
+    return
+        HashPtrTable<IOobject>::filterKeys
+        (
+            [](const word& k){ return k.endsWith("_0"); },
+            true  // prune
+        );
+}
+
+
+Foam::wordList Foam::IOobjectList::allNames() const
+{
+    wordList objNames(HashPtrTable<IOobject>::toc());
+
+    syncNames(objNames);
+    return objNames;
+}
+
+
+bool Foam::IOobjectList::checkNames(const bool syncPar) const
+{
+    if (syncPar && Pstream::parRun())
+    {
+        wordList objNames(HashPtrTable<IOobject>::toc());
+
+        return checkNames(objNames, syncPar);
+    }
+
+    return true;
 }
 
 
diff --git a/src/OpenFOAM/db/IOobjectList/IOobjectList.H b/src/OpenFOAM/db/IOobjectList/IOobjectList.H
index 3496e47d20c3b27c95d2f746c225b1d122da47d8..692e81c8905776b82a1961bd9efb7d6f0285a703 100644
--- a/src/OpenFOAM/db/IOobjectList/IOobjectList.H
+++ b/src/OpenFOAM/db/IOobjectList/IOobjectList.H
@@ -76,6 +76,24 @@ class IOobjectList
             const MatchPredicate& matchName
         );
 
+        //- Templated implementation for count()
+        //  The number of items with a matching class
+        template<class MatchPredicate1, class MatchPredicate2>
+        static label countImpl
+        (
+            const IOobjectList& list,
+            const MatchPredicate1& matchClass,
+            const MatchPredicate2& matchName
+        );
+
+        //- Templated implementation for count()
+        template<class Type, class MatchPredicate>
+        static label countTypeImpl
+        (
+            const IOobjectList& list,
+            const MatchPredicate& matchName
+        );
+
         //- Templated implementation for names(), sortedNames()
         template<class MatchPredicate1, class MatchPredicate2>
         static wordList namesImpl
@@ -83,8 +101,16 @@ class IOobjectList
             const IOobjectList& list,
             const MatchPredicate1& matchClass,
             const MatchPredicate2& matchName,
-            const bool doSort,
-            const bool syncPar
+            const bool doSort
+        );
+
+        //- Templated implementation for names(), sortedNames()
+        template<class Type, class MatchPredicate>
+        static wordList namesTypeImpl
+        (
+            const IOobjectList& list,
+            const MatchPredicate& matchName,
+            const bool doSort
         );
 
         //- Templated implementation for lookup()
@@ -104,6 +130,14 @@ class IOobjectList
             const MatchPredicate2& matchName
         );
 
+        //- Templated implementation for lookupClass()
+        template<class Type, class MatchPredicate>
+        static IOobjectList lookupClassTypeImpl
+        (
+            const IOobjectList& list,
+            const MatchPredicate& matchName
+        );
+
 
 public:
 
@@ -181,17 +215,38 @@ public:
 
     // Lookup multiple items
 
-        //- The list of all IOobjects that have a matching object name.
+        //- The list of IOobjects that have a matching object name.
         template<class MatchPredicate>
         IOobjectList lookup(const MatchPredicate& matchName) const;
 
-        //- The list of all IOobjects with the given headerClassName
+        //- The list of IOobjects with the given headerClassName
         IOobjectList lookupClass(const char* clsName) const;
 
-        //- The list of all IOobjects with matching headerClassName
+        //- The list of IOobjects with matching headerClassName
         template<class MatchPredicate>
         IOobjectList lookupClass(const MatchPredicate& matchClass) const;
 
+        //- The list of IOobjects with matching headerClassName
+        //- that also have a matching object name.
+        template<class MatchPredicate1, class MatchPredicate2>
+        IOobjectList lookupClass
+        (
+            const MatchPredicate1& matchClass,
+            const MatchPredicate2& matchName
+        ) const;
+
+        //- The list of IOobjects with headerClassName == Type::typeName
+        //
+        //  \note If \a Type is \c void, no headerClassName check is used
+        //      (always true).
+        template<class Type>
+        IOobjectList lookupClass() const;
+
+        //- The list of IOobjects with headerClassName == Type::typeName
+        //- that also have a matching object name.
+        template<class Type, class MatchPredicate>
+        IOobjectList lookupClass(const MatchPredicate& matchName) const;
+
 
     // Summary of classes
 
@@ -273,6 +328,41 @@ public:
         HashTable<wordHashSet> classes(const MatchPredicate& matchName) const;
 
 
+    // Number of items
+
+        //- The number of objects of the given headerClassName
+        //  \note uses the class type() method
+        label count(const char* clsName) const;
+
+        //- The number of objects of the given headerClassName
+        template<class MatchPredicate>
+        label count
+        (
+            const MatchPredicate& matchClass
+        ) const;
+
+        //- The number of objects of the given headerClassName
+        //- that also have a matching object name.
+        template<class MatchPredicate1, class MatchPredicate2>
+        label count
+        (
+            const MatchPredicate1& matchClass,
+            const MatchPredicate2& matchName
+        ) const;
+
+        //- The number of objects with headerClassName == Type::typeName
+        template<class Type>
+        label count() const;
+
+        //- The number of objects with headerClassName == Type::typeName
+        //- that also have a matching object name.
+        //
+        //  \note If \a Type is \c void, no headerClassName check is used
+        //      (always true).
+        template<class Type, class MatchPredicate>
+        label count(const MatchPredicate& matchName) const;
+
+
     // Summary of names
 
         //- The names of the IOobjects
@@ -283,31 +373,74 @@ public:
         //  if the names are not consistent on all processors.
         wordList names(const bool syncPar) const;
 
-        //- The names of IOobjects with the given class
-        wordList names(const word& clsName) const;
+        //- The names of IOobjects with the given headerClassName
+        wordList names(const char* clsName) const;
 
         //- The names of the IOobjects with the given headerClassName
         //  With syncPar = true, sorts the names and triggers FatalError
         //  if the names are not consistent on all processors.
-        wordList names(const word& clsName, const bool syncPar) const;
+        wordList names(const char* clsName, const bool syncPar) const;
 
         //- The names of IOobjects with the given headerClassName
-        //- that also have a matching object name.
+        template<class MatchPredicate>
+        wordList names(const MatchPredicate& matchClass) const;
+
+        //- The names of the IOobjects with the given headerClassName
+        //  With syncPar = true, sorts the names and triggers FatalError
+        //  if the names are not consistent on all processors.
         template<class MatchPredicate>
         wordList names
         (
-            const word& clsName,
-            const MatchPredicate& matchName
+            const MatchPredicate& matchClass,
+            const bool syncPar
+        ) const;
+
+        //- The names of IOobjects with the given headerClassName
+        //- that also have a matching object name.
+        template<class MatchPredicate1, class MatchPredicate2>
+        wordList names
+        (
+            const MatchPredicate1& matchClass,
+            const MatchPredicate2& matchName
         ) const;
 
         //- The names of the IOobjects with the given headerClassName
         //- that also have a matching object name.
         //  With syncPar = true, sorts the names and triggers FatalError
         //  if the names are not consistent on all processors.
-        template<class MatchPredicate>
+        template<class MatchPredicate1, class MatchPredicate2>
+        wordList names
+        (
+            const MatchPredicate1& matchClass,
+            const MatchPredicate2& matchName,
+            const bool syncPar
+        ) const;
+
+
+        //- The names of objects with headerClassName == Type::typeName
+        template<class Type>
+        wordList names() const;
+
+        //- The names of objects with headerClassName == Type::typeName
+        //  With syncPar = true, sorts the names and triggers FatalError
+        //  if the names are not consistent on all processors.
+        template<class Type>
+        wordList names(bool syncPar) const;
+
+        //- The names of objects with headerClassName == Type::typeName
+        //- that also have a matching object name.
+        //  With syncPar = true, sorts the names and triggers FatalError
+        //  if the names are not consistent on all processors.
+        template<class Type, class MatchPredicate>
+        wordList names(const MatchPredicate& matchName) const;
+
+        //- The names of objects with headerClassName == Type::typeName
+        //- that also have a matching object name.
+        //  With syncPar = true, sorts the names and triggers FatalError
+        //  if the names are not consistent on all processors.
+        template<class Type, class MatchPredicate>
         wordList names
         (
-            const word& clsName,
             const MatchPredicate& matchName,
             const bool syncPar
         ) const;
@@ -318,41 +451,125 @@ public:
         //- The sorted names of the IOobjects
         wordList sortedNames() const;
 
-        //- The sorted names of the IOobjects
-        //  With syncPar = true, a FatalError is
-        //  triggered if the names are not consistent on all processors.
+        //- The sorted names of the IOobjects.
+        //  With syncPar = true, sorts the names and triggers FatalError
+        //  if the names are not consistent on all processors.
         wordList sortedNames(const bool syncPar) const;
 
         //- The sorted names of IOobjects with the given headerClassName
-        wordList sortedNames(const word& clsName) const;
+        wordList sortedNames(const char* clsName) const;
 
         //- The sorted names of the IOobjects with the given headerClassName
         //  With syncPar = true, sorts the names and triggers FatalError
         //  if the names are not consistent on all processors.
-        wordList sortedNames(const word& clsName, const bool syncPar) const;
+        wordList sortedNames(const char* clsName, const bool syncPar) const;
 
         //- The sorted names of IOobjects with the given headerClassName
-        //- that also have a matching object name.
+        template<class MatchPredicate>
+        wordList sortedNames(const MatchPredicate& matchClass) const;
+
+        //- The sorted names of the IOobjects with the given headerClassName
+        //  With syncPar = true, sorts the names and triggers FatalError
+        //  if the names are not consistent on all processors.
         template<class MatchPredicate>
         wordList sortedNames
         (
-            const word& clsName,
-            const MatchPredicate& matchName
+            const MatchPredicate& matchClass,
+            const bool syncPar
+        ) const;
+
+        //- The sorted names of IOobjects with the given headerClassName
+        //- that also have a matching object name.
+        template<class MatchPredicate1, class MatchPredicate2>
+        wordList sortedNames
+        (
+            const MatchPredicate1& matchClass,
+            const MatchPredicate2& matchName
         ) const;
 
         //- The sorted names of the IOobjects with the given headerClassName
         //- that also have a matching object name.
         //  With syncPar = true, sorts the names and triggers FatalError
         //  if the names are not consistent on all processors.
-        template<class MatchPredicate>
+        template<class MatchPredicate1, class MatchPredicate2>
+        wordList sortedNames
+        (
+            const MatchPredicate1& matchClass,
+            const MatchPredicate2& matchName,
+            const bool syncPar
+        ) const;
+
+
+        //- The sorted names of objects with headerClassName == Type::typeName
+        template<class Type>
+        wordList sortedNames() const;
+
+        //- The sorted names of objects with headerClassName == Type::typeName
+        //  With syncPar = true, sorts the names and triggers FatalError
+        //  if the names are not consistent on all processors.
+        template<class Type>
+        wordList sortedNames(bool syncPar) const;
+
+        //- The sorted names of objects with headerClassName == Type::typeName
+        //- that also have a matching object name.
+        //  With syncPar = true, sorts the names and triggers FatalError
+        //  if the names are not consistent on all processors.
+        template<class Type, class MatchPredicate>
+        wordList sortedNames(const MatchPredicate& matchName) const;
+
+        //- The sorted names of objects with headerClassName == Type::typeName
+        //- that also have a matching object name.
+        //  With syncPar = true, sorts the names and triggers FatalError
+        //  if the names are not consistent on all processors.
+        template<class Type, class MatchPredicate>
         wordList sortedNames
         (
-            const word& clsName,
             const MatchPredicate& matchName,
             const bool syncPar
         ) const;
 
 
+    // Edit
+
+        //- Filter to retain or prune given classes
+        //  \return The number of items changed (removed)
+        template<class UnaryPredicate>
+        label filterClasses
+        (
+            const UnaryPredicate& pred,
+            const bool pruning = false
+        );
+
+        //- Filter to retain or prune given object names
+        //  \return The number of items changed (removed)
+        template<class UnaryPredicate>
+        label filterObjects
+        (
+            const UnaryPredicate& pred,
+            const bool pruning = false
+        );
+
+        //- Remove objects with names ending with "_0" (restart fields)
+        //  \return The number of items changed (removed)
+        label prune_0();
+
+
+    // Parallel
+
+        //- The sorted names of all objects (synchronised across processors)
+        wordList allNames() const;
+
+        //- The sorted names of all objects (synchronised across processors)
+        //- with headerClassName == Type::typeName
+        template<class Type>
+        wordList allNames() const;
+
+        //- Verify that object names are synchronised across processors
+        //  Triggers FatalError if the names are not consistent on all
+        //  processors.
+        bool checkNames(const bool syncPar = true) const;
+
+
     // Member Operators
 
         //- No copy assignment
diff --git a/src/OpenFOAM/db/IOobjectList/IOobjectListTemplates.C b/src/OpenFOAM/db/IOobjectList/IOobjectListTemplates.C
index 2dd17f84060fd6562e29d7e1fa1df58e4a95a248..b7dc5b9b37305d0be87692ad736dac1b23d02ba3 100644
--- a/src/OpenFOAM/db/IOobjectList/IOobjectListTemplates.C
+++ b/src/OpenFOAM/db/IOobjectList/IOobjectListTemplates.C
@@ -55,6 +55,55 @@ Foam::HashTable<Foam::wordHashSet> Foam::IOobjectList::classesImpl
 }
 
 
+// Templated implementation for count()
+template<class MatchPredicate1, class MatchPredicate2>
+Foam::label Foam::IOobjectList::countImpl
+(
+    const IOobjectList& list,
+    const MatchPredicate1& matchClass,
+    const MatchPredicate2& matchName
+)
+{
+    label count = 0;
+
+    forAllConstIters(list, iter)
+    {
+        const IOobject* io = iter.object();
+
+        if (matchClass(io->headerClassName()) && matchName(io->name()))
+        {
+            ++count;
+        }
+    }
+
+    return count;
+}
+
+
+// Templated implementation for count()
+template<class Type, class MatchPredicate>
+Foam::label Foam::IOobjectList::countTypeImpl
+(
+    const IOobjectList& list,
+    const MatchPredicate& matchName
+)
+{
+    label count = 0;
+
+    forAllConstIters(list, iter)
+    {
+        const IOobject* io = iter.object();
+
+        if (io->isHeaderClassName<Type>() && matchName(io->name()))
+        {
+            ++count;
+        }
+    }
+
+    return count;
+}
+
+
 // Templated implementation for names(), sortedNames()
 template<class MatchPredicate1, class MatchPredicate2>
 Foam::wordList Foam::IOobjectList::namesImpl
@@ -62,8 +111,7 @@ Foam::wordList Foam::IOobjectList::namesImpl
     const IOobjectList& list,
     const MatchPredicate1& matchClass,
     const MatchPredicate2& matchName,
-    const bool doSort,
-    const bool syncPar
+    const bool doSort
 )
 {
     wordList objNames(list.size());
@@ -81,14 +129,47 @@ Foam::wordList Foam::IOobjectList::namesImpl
         }
     }
 
-    objNames.setSize(count);
+    objNames.resize(count);
 
     if (doSort)
     {
         Foam::sort(objNames);
     }
 
-    checkNames(objNames, syncPar);
+    return objNames;
+}
+
+
+// Templated implementation for names(), sortedNames()
+template<class Type, class MatchPredicate>
+Foam::wordList Foam::IOobjectList::namesTypeImpl
+(
+    const IOobjectList& list,
+    const MatchPredicate& matchName,
+    const bool doSort
+)
+{
+    wordList objNames(list.size());
+
+    label count = 0;
+    forAllConstIters(list, iter)
+    {
+        const word& key = iter.key();
+        const IOobject* io = iter.object();
+
+        if (io->isHeaderClassName<Type>() && matchName(key))
+        {
+            objNames[count] = key;
+            ++count;
+        }
+    }
+
+    objNames.resize(count);
+
+    if (doSort)
+    {
+        Foam::sort(objNames);
+    }
 
     return objNames;
 }
@@ -155,6 +236,36 @@ Foam::IOobjectList Foam::IOobjectList::lookupClassImpl
 }
 
 
+// Templated implementation for lookupClass()
+template<class Type, class MatchPredicate>
+Foam::IOobjectList Foam::IOobjectList::lookupClassTypeImpl
+(
+    const IOobjectList& list,
+    const MatchPredicate& matchName
+)
+{
+    IOobjectList results(list.size());
+
+    forAllConstIters(list, iter)
+    {
+        const word& key = iter.key();
+        const IOobject* io = iter.object();
+
+        if (io->isHeaderClassName<Type>() && matchName(key))
+        {
+            if (IOobject::debug)
+            {
+                InfoInFunction << "Found " << key << endl;
+            }
+
+            results.set(key, new IOobject(*io));
+        }
+    }
+
+    return results;
+}
+
+
 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
 
 template<class MatchPredicate>
@@ -177,6 +288,34 @@ Foam::IOobjectList Foam::IOobjectList::lookupClass
 }
 
 
+template<class MatchPredicate1, class MatchPredicate2>
+Foam::IOobjectList Foam::IOobjectList::lookupClass
+(
+    const MatchPredicate1& matchClass,
+    const MatchPredicate2& matchName
+) const
+{
+    return lookupClassImpl(*this, matchClass, matchName);
+}
+
+
+template<class Type>
+Foam::IOobjectList Foam::IOobjectList::lookupClass() const
+{
+    return lookupClassTypeImpl<Type>(*this, predicates::always());
+}
+
+
+template<class Type, class MatchPredicate>
+Foam::IOobjectList Foam::IOobjectList::lookupClass
+(
+    const MatchPredicate& matchName
+) const
+{
+    return lookupClassImpl<Type>(*this, matchName);
+}
+
+
 template<class MatchPredicate>
 Foam::HashTable<Foam::wordHashSet>
 Foam::IOobjectList::classes
@@ -189,52 +328,283 @@ Foam::IOobjectList::classes
 
 
 template<class MatchPredicate>
-Foam::wordList Foam::IOobjectList::names
+Foam::label Foam::IOobjectList::count
+(
+    const MatchPredicate& matchClass
+) const
+{
+    return countImpl(*this, matchClass, predicates::always());
+}
+
+
+template<class MatchPredicate1, class MatchPredicate2>
+Foam::label Foam::IOobjectList::count
+(
+    const MatchPredicate1& matchClass,
+    const MatchPredicate2& matchName
+) const
+{
+    return countImpl(*this, matchClass, matchName);
+}
+
+
+template<class Type>
+Foam::label Foam::IOobjectList::count() const
+{
+    return countTypeImpl<Type>(*this, predicates::always());
+}
+
+
+template<class Type, class MatchPredicate>
+Foam::label Foam::IOobjectList::count
 (
-    const word& clsName,
     const MatchPredicate& matchName
 ) const
 {
-    // sort/sync: false, false
-    return namesImpl(*this, clsName, matchName, false, false);
+    return countTypeImpl<Type>(*this, matchName);
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+template<class MatchPredicate>
+Foam::wordList Foam::IOobjectList::names
+(
+    const MatchPredicate& matchClass
+) const
+{
+    return namesImpl(*this, matchClass, predicates::always(), false);
 }
 
 
 template<class MatchPredicate>
 Foam::wordList Foam::IOobjectList::names
 (
-    const word& clsName,
+    const MatchPredicate& matchClass,
+    const bool syncPar
+) const
+{
+    wordList objNames
+    (
+        namesImpl(*this, matchClass, predicates::always(), false)
+    );
+
+    checkNames(objNames, syncPar);
+    return objNames;
+}
+
+
+template<class MatchPredicate1, class MatchPredicate2>
+Foam::wordList Foam::IOobjectList::names
+(
+    const MatchPredicate1& matchClass,
+    const MatchPredicate2& matchName
+) const
+{
+    return namesImpl(*this, matchClass, matchName, false);
+}
+
+
+template<class MatchPredicate1, class MatchPredicate2>
+Foam::wordList Foam::IOobjectList::names
+(
+    const MatchPredicate1& matchClass,
+    const MatchPredicate2& matchName,
+    const bool syncPar
+) const
+{
+    wordList objNames(namesImpl(*this, matchClass, matchName, false));
+
+    checkNames(objNames, syncPar);
+    return objNames;
+}
+
+
+template<class Type>
+Foam::wordList Foam::IOobjectList::names() const
+{
+    return namesTypeImpl<Type>(*this, predicates::always(), false);
+}
+
+
+template<class Type>
+Foam::wordList Foam::IOobjectList::names(const bool syncPar) const
+{
+    wordList objNames(namesTypeImpl<Type>(*this, predicates::always(), false));
+
+    checkNames(objNames, syncPar);
+    return objNames;
+}
+
+
+template<class Type, class MatchPredicate>
+Foam::wordList Foam::IOobjectList::names
+(
+    const MatchPredicate& matchName
+) const
+{
+    return namesTypeImpl<Type>(*this, matchName, false);
+}
+
+
+template<class Type, class MatchPredicate>
+Foam::wordList Foam::IOobjectList::names
+(
     const MatchPredicate& matchName,
     const bool syncPar
 ) const
 {
-    // sort: false
-    return namesImpl(*this, clsName, matchName, false, syncPar);
+    wordList objNames(namesTypeImpl<Type>(*this, matchName, false));
+
+    checkNames(objNames, syncPar);
+    return objNames;
 }
 
 
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
 template<class MatchPredicate>
 Foam::wordList Foam::IOobjectList::sortedNames
 (
-    const word& clsName,
-    const MatchPredicate& matchName
+    const MatchPredicate& matchClass
 ) const
 {
-    // sort/sync: true, false
-    return namesImpl(*this, clsName, matchName, true, false);
+    return namesImpl(*this, matchClass, predicates::always(), true);
 }
 
 
 template<class MatchPredicate>
 Foam::wordList Foam::IOobjectList::sortedNames
 (
-    const word& clsName,
+    const MatchPredicate& matchClass,
+    const bool syncPar
+) const
+{
+    wordList objNames
+    (
+        namesImpl(*this, matchClass, predicates::always(), true)
+    );
+
+    checkNames(objNames, syncPar);
+    return objNames;
+}
+
+
+template<class MatchPredicate1, class MatchPredicate2>
+Foam::wordList Foam::IOobjectList::sortedNames
+(
+    const MatchPredicate1& matchClass,
+    const MatchPredicate2& matchName
+) const
+{
+    return namesImpl(*this, matchClass, matchName, true);
+}
+
+template<class MatchPredicate1, class MatchPredicate2>
+Foam::wordList Foam::IOobjectList::sortedNames
+(
+    const MatchPredicate1& matchClass,
+    const MatchPredicate2& matchName,
+    const bool syncPar
+) const
+{
+    wordList objNames(namesImpl(*this, matchClass, matchName, true));
+
+    checkNames(objNames, syncPar);
+    return objNames;
+}
+
+
+template<class Type>
+Foam::wordList Foam::IOobjectList::sortedNames() const
+{
+    return namesTypeImpl<Type>(*this, predicates::always(), true);
+}
+
+
+template<class Type>
+Foam::wordList Foam::IOobjectList::sortedNames(const bool syncPar) const
+{
+    wordList objNames(namesTypeImpl<Type>(*this, predicates::always(), true));
+
+    checkNames(objNames, syncPar);
+    return objNames;
+}
+
+
+template<class Type, class MatchPredicate>
+Foam::wordList Foam::IOobjectList::sortedNames
+(
+    const MatchPredicate& matchName
+) const
+{
+    return namesTypeImpl<Type>(*this, matchName, true);
+}
+
+
+template<class Type, class MatchPredicate>
+Foam::wordList Foam::IOobjectList::sortedNames
+(
     const MatchPredicate& matchName,
     const bool syncPar
 ) const
 {
-    // sort: true
-    return namesImpl(*this, clsName, matchName, true, syncPar);
+    return namesTypeImpl<Type>(*this, matchName, true, syncPar);
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+template<class UnaryPredicate>
+Foam::label Foam::IOobjectList::filterClasses
+(
+    const UnaryPredicate& pred,
+    const bool pruning
+)
+{
+//    return HashPtrTable<IOobject>::filterValues
+//    (
+//        [&](const IOobject* io){ return pred(io->headerClassName()); },
+//        pruning
+//    );
+
+    label changed = 0;
+
+    for (iterator iter = begin(); iter != end(); ++iter)
+    {
+        // Matches? either prune (pruning) or keep (!pruning)
+        if
+        (
+            (pred(iter.object()->headerClassName()) ? pruning : !pruning)
+         && erase(iter)
+        )
+        {
+            ++changed;
+        }
+    }
+
+    return changed;
+}
+
+
+template<class UnaryPredicate>
+Foam::label Foam::IOobjectList::filterObjects
+(
+    const UnaryPredicate& pred,
+    const bool pruning
+)
+{
+    return HashPtrTable<IOobject>::filterKeys(pred, pruning);
+}
+
+
+template<class Type>
+Foam::wordList Foam::IOobjectList::allNames() const
+{
+    wordList objNames(namesTypeImpl<Type>(*this, predicates::always(), false));
+
+    syncNames(objNames);
+    return objNames;
 }
 
 
diff --git a/src/OpenFOAM/db/objectRegistry/objectRegistry.C b/src/OpenFOAM/db/objectRegistry/objectRegistry.C
index b91a94d228d1fc45c0690b2af572a24280391e04..a747de2c83a49580e23445227fbf380ea3387e8f 100644
--- a/src/OpenFOAM/db/objectRegistry/objectRegistry.C
+++ b/src/OpenFOAM/db/objectRegistry/objectRegistry.C
@@ -111,24 +111,10 @@ Foam::HashTable<Foam::wordHashSet> Foam::objectRegistry::classes() const
 }
 
 
-Foam::HashTable<Foam::wordHashSet>
-Foam::objectRegistry::classes(const wordRe& matchName) const
+Foam::label Foam::objectRegistry::count(const char* clsName) const
 {
-    return classesImpl(*this, matchName);
-}
-
-
-Foam::HashTable<Foam::wordHashSet>
-Foam::objectRegistry::classes(const wordRes& matchName) const
-{
-    return classesImpl(*this, matchName);
-}
-
-
-Foam::HashTable<Foam::wordHashSet>
-Foam::objectRegistry::classes(const wordHashSet& matchName) const
-{
-    return classesImpl(*this, matchName);
+    // No nullptr check - only called with string literals
+    return count(static_cast<word>(clsName));
 }
 
 
@@ -144,31 +130,17 @@ Foam::wordList Foam::objectRegistry::sortedNames() const
 }
 
 
-Foam::wordList Foam::objectRegistry::names(const word& clsName) const
+Foam::wordList Foam::objectRegistry::names(const char* clsName) const
 {
-    wordList objNames(size());
-
-    label count=0;
-    for (const_iterator iter = cbegin(); iter != cend(); ++iter)
-    {
-        if (iter()->type() == clsName)
-        {
-            objNames[count++] = iter.key();
-        }
-    }
-
-    objNames.setSize(count);
-
-    return objNames;
+    // No nullptr check - only called with string literals
+    return names(static_cast<word>(clsName));
 }
 
 
-Foam::wordList Foam::objectRegistry::sortedNames(const word& clsName) const
+Foam::wordList Foam::objectRegistry::sortedNames(const char* clsName) const
 {
-    wordList objNames = names(clsName);
-    Foam::sort(objNames);
-
-    return objNames;
+    // No nullptr check - only called with string literals
+    return sortedNames(static_cast<word>(clsName));
 }
 
 
diff --git a/src/OpenFOAM/db/objectRegistry/objectRegistry.H b/src/OpenFOAM/db/objectRegistry/objectRegistry.H
index 8a92fbd26e59873bdece219401e61a0cbbd15bb8..d05f5edf0a4cc15430bc44c3cab8f1948acfc387 100644
--- a/src/OpenFOAM/db/objectRegistry/objectRegistry.H
+++ b/src/OpenFOAM/db/objectRegistry/objectRegistry.H
@@ -81,6 +81,25 @@ class objectRegistry
         //  Used to terminate searching within the ancestors
         bool parentNotTime() const;
 
+        //- Templated implementation for count()
+        //  The number of items with a matching class
+        template<class MatchPredicate1, class MatchPredicate2>
+        static label countImpl
+        (
+            const objectRegistry& list,
+            const MatchPredicate1& matchClass,
+            const MatchPredicate2& matchName
+        );
+
+        //- Templated implementation for count()
+        //  The number of items with a matching class
+        template<class Type, class MatchPredicate>
+        static label countTypeImpl
+        (
+            const objectRegistry& list,
+            const MatchPredicate& matchName
+        );
+
         //- Templated implementation for classes()
         template<class MatchPredicate>
         static HashTable<wordHashSet> classesImpl
@@ -89,6 +108,16 @@ class objectRegistry
             const MatchPredicate& matchName
         );
 
+        //- Templated implementation for names(), sortedNames()
+        template<class MatchPredicate1, class MatchPredicate2>
+        static wordList namesImpl
+        (
+            const objectRegistry& list,
+            const MatchPredicate1& matchClass,
+            const MatchPredicate2& matchName,
+            const bool doSort
+        );
+
         //- Templated implementation for names(), sortedNames()
         template<class Type, class MatchPredicate>
         static wordList namesTypeImpl
@@ -157,90 +186,125 @@ public:
         //  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& matchName) 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& matchName) const;
+        //- A summary hash of classes used and their associated object names,
+        //- restricted to objects that have a matching object name.
+        template<class MatchPredicate>
+        HashTable<wordHashSet> classes(const MatchPredicate& matchName) 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 wordHashSet& matchName) const;
 
+    // Number of items
 
-    // Summary of names
+        //- The number of objects of the given class name
+        //  \note uses the class type() method
+        label count(const char* clsName) const;
 
-        //- The names of the objects
-        wordList names() const;
+        //- The number of objects of the given class name
+        //  \note uses the class type() method
+        template<class MatchPredicate>
+        label count(const MatchPredicate& matchClass) const;
 
-        //- The names of objects with the given class
-        wordList names(const word& clsName) const;
+        //- The number of objects of the given class name
+        //  \note uses the class type() method
+        template<class MatchPredicate1, class MatchPredicate2>
+        label count
+        (
+            const MatchPredicate1& matchClass,
+            const MatchPredicate2& matchName
+        ) const;
 
-        //- The names of objects with a class satisfying \c isA\<Type\>.
+        //- The names of objects with a class satisfying \c isA\<Type\>
+        //
+        //  \param strict use \c isType\<Type\> instead of \c isA\<Type\>
         //
+        //  \note The values of \c count\<Type\>() and \c count(Type::typeName)
+        //      may be inconsistent, since they use different mechanisms for
+        //      testing the class type.
         //  \note If \a Type is \c void, no isA check is used (always true).
         template<class Type>
-        wordList names() const;
+        label count(const bool strict = false) const;
 
         //- The names of objects with a class satisfying \c isA\<Type\>
-        //- that also have a name satisfying the input matcher
+        //- that also have a matching object name.
         //
         //  \note If \a Type is \c void, no isA check is used (always true).
-        template<class Type>
-        wordList names(const wordRe& matchName) const;
+        template<class Type, class MatchPredicate>
+        label count(const MatchPredicate& matchName) const;
 
-        //- The names of objects with a class satisfying \c isA\<Type\>
-        //- that also have a name satisfying the input matcher
+
+    // Summary of names
+
+        //- The names of all objects
+        wordList names() const;
+
+        //- The names of objects with the given class name.
+        //  \note uses the class type() method
+        wordList names(const char* clsName) const;
+
+        //- The names of objects with a matching class name
+        //  \note uses the class type() method
+        template<class MatchPredicate>
+        wordList names(const MatchPredicate& matchClass) const;
+
+        //- The names of objects with a matching class name
+        //- that also have a matching object name.
+        //  \note uses the class type() method
+        template<class MatchPredicate1, class MatchPredicate2>
+        wordList names
+        (
+            const MatchPredicate1& matchClass,
+            const MatchPredicate2& matchName
+        ) const;
+
+        //- The names of objects with a class satisfying \c isA\<Type\>.
         //
         //  \note If \a Type is \c void, no isA check is used (always true).
         template<class Type>
-        wordList names(const wordRes& matchName) const;
+        wordList names() const;
 
         //- The names of objects with a class satisfying \c isA\<Type\>
-        //- that also have a name satisfying the input matcher
+        //- that also have a matching object name.
         //
         //  \note If \a Type is \c void, no isA check is used (always true).
-        template<class Type>
-        wordList names(const wordHashSet& matchName) const;
+        template<class Type, class MatchPredicate>
+        wordList names(const MatchPredicate& matchName) const;
 
 
     // Summary of names (sorted)
 
-        //- The sorted names of the objects
+        //- The sorted names of all objects
         wordList sortedNames() const;
 
-        //- The sorted names of objects with the given class
-        wordList sortedNames(const word& clsName) const;
+        //- The sorted names of objects with the given class name.
+        //  \note uses the class type() method
+        wordList sortedNames(const char* clsName) const;
 
-        //- The sorted names of objects with a class satisfying \c isA\<Type\>
-        //- that also have a name satisfying the input matcher
-        //
-        //  \note If \a Type is \c void, no isA check is used (always true).
-        template<class Type>
-        wordList sortedNames() const;
+        //- The sorted names objects with a matching class name
+        //  \note uses the class type() method
+        template<class MatchPredicate>
+        wordList sortedNames(const MatchPredicate& matchClass) const;
 
-        //- The sorted names of objects with a class satisfying \c isA\<Type\>
-        //- that also have a name satisfying the input matcher
-        //
-        //  \note If \a Type is \c void, no isA check is used (always true).
-        template<class Type>
-        wordList sortedNames(const wordRe& matchName) const;
+        //- The sorted names of objects with a matching class name
+        //- that also have a matching object name.
+        //  \note uses the class type() method
+        template<class MatchPredicate1, class MatchPredicate2>
+        wordList sortedNames
+        (
+            const MatchPredicate1& matchClass,
+            const MatchPredicate2& matchName
+        ) const;
 
         //- The sorted names of objects with a class satisfying \c isA\<Type\>
-        //- that also have a name satisfying the input matcher
         //
         //  \note If \a Type is \c void, no isA check is used (always true).
         template<class Type>
-        wordList sortedNames(const wordRes& matchName) const;
+        wordList sortedNames() const;
 
         //- The sorted names of objects with a class satisfying \c isA\<Type\>
-        //- that also have a name satisfying the input matcher
+        //- that also have a matching object name.
         //
         //  \note If \a Type is \c void, no isA check is used (always true).
-        template<class Type>
-        wordList sortedNames(const wordHashSet& matchName) const;
+        template<class Type, class MatchPredicate>
+        wordList sortedNames(const MatchPredicate& matchName) const;
 
 
     // Lookup
diff --git a/src/OpenFOAM/db/objectRegistry/objectRegistryTemplates.C b/src/OpenFOAM/db/objectRegistry/objectRegistryTemplates.C
index 20740e07d05b8ac8f70d3071ec083ebe660c8520..e75a304edae4462e03284506fe9de255f4eb001c 100644
--- a/src/OpenFOAM/db/objectRegistry/objectRegistryTemplates.C
+++ b/src/OpenFOAM/db/objectRegistry/objectRegistryTemplates.C
@@ -42,10 +42,12 @@ Foam::HashTable<Foam::wordHashSet> Foam::objectRegistry::classesImpl
     // Summary (key,val) = (class-name, object-names)
     forAllConstIters(list, iter)
     {
-        if (matchName(iter.key()))
+        const regIOobject* obj = iter.object();
+
+        if (matchName(obj->name()))
         {
             // Create entry (if needed) and insert
-            summary(iter.object()->type()).insert(iter.key());
+            summary(iter.object()->type()).insert(obj->name());
         }
     }
 
@@ -53,6 +55,94 @@ Foam::HashTable<Foam::wordHashSet> Foam::objectRegistry::classesImpl
 }
 
 
+// Templated implementation for count()
+template<class MatchPredicate1, class MatchPredicate2>
+Foam::label Foam::objectRegistry::countImpl
+(
+    const objectRegistry& list,
+    const MatchPredicate1& matchClass,
+    const MatchPredicate2& matchName
+)
+{
+    label count = 0;
+
+    forAllConstIters(list, iter)
+    {
+        const regIOobject* obj = iter.object();
+
+        if (matchClass(obj->type()) && matchName(obj->name()))
+        {
+            ++count;
+        }
+    }
+
+    return count;
+}
+
+
+// Templated implementation for count()
+template<class Type, class MatchPredicate>
+Foam::label Foam::objectRegistry::countTypeImpl
+(
+    const objectRegistry& list,
+    const MatchPredicate& matchName
+)
+{
+    label count = 0;
+
+    forAllConstIters(list, iter)
+    {
+        const regIOobject* obj = iter.object();
+
+        if
+        (
+            (std::is_void<Type>::value || isA<Type>(*obj))
+         && matchName(obj->name())
+        )
+        {
+            ++count;
+        }
+    }
+
+    return count;
+}
+
+
+// Templated implementation for names(), sortedNames()
+template<class MatchPredicate1, class MatchPredicate2>
+Foam::wordList Foam::objectRegistry::namesImpl
+(
+    const objectRegistry& list,
+    const MatchPredicate1& matchClass,
+    const MatchPredicate2& matchName,
+    const bool doSort
+)
+{
+    wordList objNames(list.size());
+
+    label count=0;
+    forAllConstIters(list, iter)
+    {
+        const regIOobject* obj = iter.object();
+
+        if (matchClass(obj->type()) && matchName(obj->name()))
+        {
+            objNames[count] = obj->name();
+            ++count;
+        }
+    }
+
+    objNames.resize(count);
+
+    if (doSort)
+    {
+        Foam::sort(objNames);
+    }
+
+    return objNames;
+}
+
+
 // Templated implementation for names(), sortedNames()
 template<class Type, class MatchPredicate>
 Foam::wordList Foam::objectRegistry::namesTypeImpl
@@ -75,7 +165,7 @@ Foam::wordList Foam::objectRegistry::namesTypeImpl
          && matchName(obj->name())
         )
         {
-            objNames[count] = iter()->name();
+            objNames[count] = obj->name();
             ++count;
         }
     }
@@ -93,59 +183,144 @@ Foam::wordList Foam::objectRegistry::namesTypeImpl
 
 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
 
-template<class Type>
-Foam::wordList Foam::objectRegistry::names() const
+template<class MatchPredicate>
+Foam::HashTable<Foam::wordHashSet>
+Foam::objectRegistry::classes
+(
+    const MatchPredicate& matchName
+) const
 {
-    return namesTypeImpl<Type>(*this, predicates::always(), false);
+    return classesImpl(*this, matchName);
 }
 
 
-template<class Type>
-Foam::wordList Foam::objectRegistry::names(const wordRe& matchName) const
+template<class MatchPredicate>
+Foam::label Foam::objectRegistry::count
+(
+    const MatchPredicate& matchClass
+) const
 {
-    return namesTypeImpl<Type>(*this, matchName, false);
+    return countImpl(*this, matchClass, predicates::always());
+}
+
+
+template<class MatchPredicate1, class MatchPredicate2>
+Foam::label Foam::objectRegistry::count
+(
+    const MatchPredicate1& matchClass,
+    const MatchPredicate2& matchName
+) const
+{
+    return countImpl(*this, matchClass, matchName);
+}
+
+
+template<class Type, class MatchPredicate>
+Foam::label Foam::objectRegistry::count
+(
+    const MatchPredicate& matchName
+) const
+{
+    return countTypeImpl<Type>(*this, matchName);
 }
 
 
 template<class Type>
-Foam::wordList Foam::objectRegistry::names(const wordRes& matchName) const
+Foam::label Foam::objectRegistry::count
+(
+    const bool strict
+) const
 {
-    return namesTypeImpl<Type>(*this, matchName, false);
+    label nObjects = 0;
+
+    forAllConstIters(*this, iter)
+    {
+        const regIOobject* obj = iter.object();
+
+        if
+        (
+            std::is_void<Type>::value
+         || (strict ? isType<Type>(*obj) : bool(isA<Type>(*obj)))
+        )
+        {
+            ++nObjects;
+        }
+    }
+
+    return nObjects;
+}
+
+
+template<class MatchPredicate>
+Foam::wordList Foam::objectRegistry::names
+(
+    const MatchPredicate& matchClass
+) const
+{
+    return namesImpl(*this, matchClass, predicates::always(), false);
+}
+
+
+template<class MatchPredicate1, class MatchPredicate2>
+Foam::wordList Foam::objectRegistry::names
+(
+    const MatchPredicate1& matchClass,
+    const MatchPredicate2& matchName
+) const
+{
+    return namesImpl(*this, matchClass, matchName, false);
 }
 
 
 template<class Type>
-Foam::wordList Foam::objectRegistry::names(const wordHashSet& matchName) const
+Foam::wordList Foam::objectRegistry::names() const
+{
+    return namesTypeImpl<Type>(*this, predicates::always(), false);
+}
+
+
+template<class Type, class MatchPredicate>
+Foam::wordList Foam::objectRegistry::names
+(
+    const MatchPredicate& matchName
+) const
 {
     return namesTypeImpl<Type>(*this, matchName, false);
 }
 
 
-template<class Type>
-Foam::wordList Foam::objectRegistry::sortedNames() const
+template<class MatchPredicate>
+Foam::wordList Foam::objectRegistry::sortedNames
+(
+    const MatchPredicate& matchClass
+) const
 {
-    return namesTypeImpl<Type>(*this, predicates::always(), true);
+    return namesImpl(*this, matchClass, predicates::always(), true);
 }
 
 
-template<class Type>
-Foam::wordList Foam::objectRegistry::sortedNames(const wordRe& matchName) const
+template<class MatchPredicate1, class MatchPredicate2>
+Foam::wordList Foam::objectRegistry::sortedNames
+(
+    const MatchPredicate1& matchClass,
+    const MatchPredicate2& matchName
+) const
 {
-    return namesTypeImpl<Type>(*this, matchName, true);
+    return namesImpl(*this, matchClass, matchName, true);
 }
 
 
 template<class Type>
-Foam::wordList Foam::objectRegistry::sortedNames(const wordRes& matchName) const
+Foam::wordList Foam::objectRegistry::sortedNames() const
 {
-    return namesTypeImpl<Type>(*this, matchName, true);
+    return namesTypeImpl<Type>(*this, predicates::always(), true);
 }
 
 
-template<class Type>
+template<class Type, class MatchPredicate>
 Foam::wordList Foam::objectRegistry::sortedNames
 (
-    const wordHashSet& matchName
+    const MatchPredicate& matchName
 ) const
 {
     return namesTypeImpl<Type>(*this, matchName, true);
@@ -162,13 +337,11 @@ Foam::HashTable<const Type*> Foam::objectRegistry::lookupClass
 
     forAllConstIters(*this, iter)
     {
-        if (strict ? isType<Type>(*iter()) : bool(isA<Type>(*iter())))
+        const regIOobject* obj = iter.object();
+
+        if (strict ? isType<Type>(*obj) : bool(isA<Type>(*obj)))
         {
-            objectsOfClass.insert
-            (
-                iter()->name(),
-                dynamic_cast<const Type*>(iter())
-            );
+            objectsOfClass.insert(obj->name(), dynamic_cast<const Type*>(obj));
         }
     }
 
@@ -186,13 +359,11 @@ Foam::HashTable<Type*> Foam::objectRegistry::lookupClass
 
     forAllIters(*this, iter)
     {
-        if (strict ? isType<Type>(*iter()) : bool(isA<Type>(*iter())))
+        regIOobject* obj = iter.object();
+
+        if (strict ? isType<Type>(*obj) : bool(isA<Type>(*obj)))
         {
-            objectsOfClass.insert
-            (
-                iter()->name(),
-                dynamic_cast<Type*>(iter())
-            );
+            objectsOfClass.insert(obj->name(), dynamic_cast<Type*>(obj));
         }
     }