diff --git a/applications/test/edges/Test-edges.C b/applications/test/edges/Test-edges.C
index abd5f9d8a19e04938ff91801cd105c25e2105351..eda9ae0dd9f6730548cda3f7fcf81b2825d49023 100644
--- a/applications/test/edges/Test-edges.C
+++ b/applications/test/edges/Test-edges.C
@@ -31,6 +31,7 @@ Description
 
 #include "argList.H"
 #include "edgeList.H"
+#include "edgeHashes.H"
 
 using namespace Foam;
 
@@ -79,6 +80,28 @@ int main(int argc, char *argv[])
         printInfo(e4);
     }
 
+    e4.start() = e4.end() = -1;
+    Info<< "insert from list\n";
+    labelHashSet newIndices({2, -1, 2, 1, 4, 1, 2, 3});
+    e4.insert(newIndices.toc());
+    printInfo(e4);
+
+    e4.start() = e4.end() = -1;
+    Info<< "insert from list\n";
+    e4.insert({0, 5, 2, -1, 2, 1, 4, 1, 2, 3});
+    printInfo(e4);
+
+    FixedList<label, 8> otherIndices{12, 2, -1, 1, 4, 1, 2, 3};
+    e4.start() = e4.end() = -1;
+    Info<< "insert from list: " << otherIndices << nl;
+    e4.insert(otherIndices);
+    printInfo(e4);
+
+    e4.start() = e4.end();
+    Info<< "erase from list: " << otherIndices << nl;
+    Info<< "removed " << e4.erase(otherIndices) << " values" << nl;
+    printInfo(e4);
+
     for (label i : {-1, 0, 1, 3})
     {
         bool ok = e4.erase(i);
diff --git a/src/OpenFOAM/containers/Lists/FixedList/FixedList.H b/src/OpenFOAM/containers/Lists/FixedList/FixedList.H
index c969f4f4ad870afd92a23c1260200ec396f4f368..bdf75aa40101e8f61511b421a3318a09c0d88179 100644
--- a/src/OpenFOAM/containers/Lists/FixedList/FixedList.H
+++ b/src/OpenFOAM/containers/Lists/FixedList/FixedList.H
@@ -329,7 +329,7 @@ public:
         //- Return size of the largest possible FixedList
         inline label max_size() const;
 
-        //- Return true if the FixedList is empty (ie, size() is zero)
+        //- Always false since zero-sized FixedList is compile-time disabled.
         inline bool empty() const;
 
         //- Swap two FixedLists of the same type in constant time
diff --git a/src/OpenFOAM/meshes/meshShapes/edge/edge.H b/src/OpenFOAM/meshes/meshShapes/edge/edge.H
index f804fda8141f96111a69881af9fcbe3c8705d7b8..f15c901b122d198e6bdcc1575ebd08acc9edaa5a 100644
--- a/src/OpenFOAM/meshes/meshShapes/edge/edge.H
+++ b/src/OpenFOAM/meshes/meshShapes/edge/edge.H
@@ -28,6 +28,14 @@ Description
     An edge is a list of two point labels. The functionality it provides
     supports the discretisation on a 2-D flat mesh.
 
+    The edge is implemented as a FixedList of labels.
+    As well as geometrically relevant methods, it also provides methods
+    similar to HashSet for additional convenience.
+    Valid point labels are always non-negative (since they correspond to
+    addressing within the mesh). The value '-1' is used to tag invalid
+    point labels that correspond conceptually to open 'slots', which
+    can be filled with the HashSet-like functionality.
+
 SourceFiles
     edgeI.H
 
@@ -60,6 +68,24 @@ class edge
 :
     public FixedList<label, 2>
 {
+    // Private Member Functions
+
+        //- Insert values, using begin/end iterators.
+        template<class InputIter>
+        inline int insertMultiple
+        (
+            const InputIter begIter,
+            const InputIter endIter
+        );
+
+        //- Remove values, using begin/end iterators.
+        template<class InputIter>
+        inline int eraseMultiple
+        (
+            const InputIter begIter,
+            const InputIter endIter
+        );
+
 
 public:
 
@@ -91,6 +117,8 @@ public:
 
     // Member Functions
 
+      // Access
+
         //- Return start vertex label
         inline label start() const;
 
@@ -103,67 +131,138 @@ public:
         //- Return end vertex label
         inline label& end();
 
+        //- Return reverse edge as copy.
+        //  No special handling of negative point labels.
+        inline edge reverseEdge() const;
+
+
+     // Queries
+
+        //- Return the smallest point label used by the edge
+        //  No special handling of negative point labels.
+        inline label minVertex() const;
+
+        //- Return the largest point label used by the edge
+        //  No special handling of negative point labels.
+        inline label maxVertex() const;
+
+        //- True if start() is less-than end()
+        //  No special handling of negative point labels.
+        inline bool sorted() const;
+
+        //- Return true if point label is found in edge.
+        //  Always false for a negative label.
+        inline bool found(const label index) const;
+
         //- Do the edges share a common vertex index?
+        //  Negative point labels never connect.
         inline bool connects(const edge& other) const;
 
         //- Return vertex common with otherEdge or -1 on failure
+        //  Negative point labels are never considered common between edges.
         inline label commonVertex(const edge& other) const;
 
         //- Given one vertex index, return the other one.
+        //  No special treatment for negative point labels.
         inline label otherVertex(const label index) const;
 
-        //- 'Collapse' edge by marking duplicate point labels.
-        //  Duplicates point labels are marked with '-1'.
-        //  (the lower vertex is retained).
-        //  Return the collapsed size.
-        inline label collapse();
 
-        //- Return true if point label is found in edge
-        //  No special treatment for '-1'.
-        inline bool found(const label index) const;
+     // Editing
+
+        //- 'Collapse' edge by marking duplicate point labels as '-1',
+        //  the lower vertex is retained.
+        //  Return the effective size after collapsing.
+        inline int collapse();
+
+        //- Flip the edge in-place.
+        //  No special handling of negative point labels.
+        inline void flip();
+
+        //- Sort so that start() is less-than end()
+        //  No special handling of negative point labels.
+        inline void sort();
+
+
+     // Hash-like functions
 
         //- Return the number of unique, valid (non -1) point labels.
         //  Similar to a HashTable::size().
-        inline label count() const;
+        inline int count() const;
+
+        //- Return true if edge has no valid point labels.
+        inline bool empty() const;
 
-        //- Insert the index if it did not previously exist on the edge.
+        //- 'Clears' edge by setting both ends to invalid point labels.
+        inline void clear();
+
+        //- Fill any open slot with the index if it did not previously exist.
         //  Returns true on success. A negative label never inserts.
         //  Similar to a HashTable::insert().
         inline bool insert(const label index);
 
+        //- Fill open slots with the indices if they did not previously exist.
+        //  Returns true on success. Negative labels never inserts.
+        //  Return the number of slots filled.
+        //  Similar to a HashTable::insert().
+        inline int insert(const UList<label>& lst);
+
+        //- Fill open slots with the indices if they did not previously exist.
+        //  Returns true on success. Negative labels never inserts.
+        //  Return the number of slots filled.
+        //  Similar to a HashTable::insert().
+        template<unsigned AnySize>
+        inline int insert(const FixedList<label, AnySize>& lst);
+
+        //- Fill open slots with the indices if they did not previously exist.
+        //  Returns true on success. Negative labels never inserts.
+        //  Return the number of slots filled.
+        //  Similar to a HashTable::insert().
+        inline int insert(std::initializer_list<label> lst);
+
         //- Remove an existing index from the edge and set its location to '-1'.
-        //  Returns true on success. A negative label never removes.
+        //  Returns the number of changes. A negative label never removes.
         //  Similar to a HashTable::erase().
-        inline bool erase(const label index);
+        inline int erase(const label index);
 
+        //- Remove existing indices from the edge and set locations to '-1'.
+        //  Returns the number of changes.
+        inline int erase(const UList<label>& lst);
 
-        //- True if the edge is sorted such that start is less-than end
-        inline bool sorted() const;
+        //- Remove existing indices from the edge and set locations to '-1'.
+        //  Returns the number of changes.
+        template<unsigned AnySize>
+        inline int erase(const FixedList<label, AnySize>& lst);
 
-        //- Sort start/end that start is less-than end
-        inline void sort();
+        //- Remove existing indices from the edge and set locations to '-1'.
+        //  Returns the number of changes.
+        inline int erase(std::initializer_list<label> lst);
 
-        //- Flip the edge in-place.
-        inline void flip();
 
-        //- Return reverse edge
-        inline edge reverseEdge() const;
+     // Geometric functions
 
-        //- Return centre (centroid)
+        //- Return centre point (centroid) of the edge.
+        //  No special handling of negative point labels.
         inline point centre(const UList<point>& pts) const;
 
         //- Return the vector (end - start)
+        //  No special handling of negative point labels.
         inline vector vec(const UList<point>& pts) const;
 
         //- Return the unit vector (end - start)
+        //  No special handling of negative point labels.
         inline vector unitVec(const UList<point>& pts) const;
 
-        //- Return scalar magnitude
+        //- Return scalar magnitude of the edge.
+        //  No special handling of negative point labels.
         inline scalar mag(const UList<point>& pts) const;
 
         //- Return edge line
+        //  No special handling of negative point labels.
         inline linePointRef line(const UList<point>& pts) const;
 
+
+     // Comparison
+
         //- Compare edges
         //  Returns:
         //  -  0: different
diff --git a/src/OpenFOAM/meshes/meshShapes/edge/edgeI.H b/src/OpenFOAM/meshes/meshShapes/edge/edgeI.H
index b1b4f493682179a70bdd6b242626cf9ab935c449..d5d5b045124568370cba32c749cb590127a849c9 100644
--- a/src/OpenFOAM/meshes/meshShapes/edge/edgeI.H
+++ b/src/OpenFOAM/meshes/meshShapes/edge/edgeI.H
@@ -45,6 +45,66 @@ inline int Foam::edge::compare(const edge& a, const edge& b)
 }
 
 
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+
+template<class InputIter>
+inline int Foam::edge::insertMultiple
+(
+    const InputIter begIter,
+    const InputIter endIter
+)
+{
+    // Available slots.
+    // Don't use count() since it has special treatment for duplicates
+    const int maxChange = (start() < 0 ? 1 : 0) + (end() < 0 ? 1 : 0);
+
+    int changed = 0;
+    if (maxChange)
+    {
+        for (InputIter iter = begIter; iter != endIter; ++iter)
+        {
+            if (insert(*iter))
+            {
+                if (++changed >= maxChange)
+                {
+                    break;
+                }
+            }
+        }
+    }
+
+    return changed;
+}
+
+
+template<class InputIter>
+inline int Foam::edge::eraseMultiple
+(
+    const InputIter begIter,
+    const InputIter endIter
+)
+{
+    // Occupied slots.
+    // Don't use count() since it has special treatment for duplicates
+    const int maxChange = (start() >= 0 ? 1 : 0) + (end() >= 0 ? 1 : 0);
+
+    int changed = 0;
+    if (maxChange)
+    {
+        for (InputIter iter = begIter; iter != endIter; ++iter)
+        {
+            changed += erase(*iter);
+            if (changed >= maxChange)
+            {
+                break;
+            }
+        }
+    }
+
+    return changed;
+}
+
+
 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
 
 inline Foam::edge::edge()
@@ -127,27 +187,40 @@ inline Foam::label& Foam::edge::end()
 }
 
 
+inline Foam::label Foam::edge::minVertex() const
+{
+    return (start() < end() ? start() : end());
+}
+
+
+inline Foam::label Foam::edge::maxVertex() const
+{
+    return (start() > end() ? start() : end());
+}
+
+
 inline bool Foam::edge::found(const label index) const
 {
-    return (index == start() || index == end());
+    // -1: always false
+    return (index >= 0 && (index == start() || index == end()));
 }
 
 
 inline bool Foam::edge::connects(const edge& other) const
 {
-    return (other.found(this->start()) || other.found(this->end()));
+    return (other.found(start()) || other.found(end()));
 }
 
 
 inline Foam::label Foam::edge::commonVertex(const edge& other) const
 {
-    if (other.found(this->start()))
+    if (other.found(start()))
     {
-        return this->start();
+        return start();
     }
-    else if (other.found(this->end()))
+    else if (other.found(end()))
     {
-        return this->end();
+        return end();
     }
     else
     {
@@ -175,19 +248,19 @@ inline Foam::label Foam::edge::otherVertex(const label index) const
 }
 
 
-inline Foam::label Foam::edge::collapse()
+inline int Foam::edge::collapse()
 {
     // Cannot resize FixedList, so mark duplicates with '-1'
     // (the lower vertex is retained)
     // catch any '-1' (eg, if called multiple times)
 
-    label n = 2;
-    if (start() == end() || end() == -1)
+    int n = 2;
+    if (start() == end() || end() < 0)
     {
         end() = -1;
         --n;
     }
-    if (start() == -1)
+    if (start() < 0)
     {
         --n;
     }
@@ -196,15 +269,48 @@ inline Foam::label Foam::edge::collapse()
 }
 
 
-inline Foam::label Foam::edge::count() const
+inline bool Foam::edge::sorted() const
+{
+    return (start() < end());
+}
+
+
+inline void Foam::edge::sort()
+{
+    if (start() > end())
+    {
+        flip();
+    }
+}
+
+
+inline void Foam::edge::flip()
+{
+    Swap(operator[](0), operator[](1));
+}
+
+
+inline Foam::edge Foam::edge::reverseEdge() const
+{
+    return edge(end(), start());
+}
+
+
+inline void Foam::edge::clear()
+{
+    start() = -1;
+    end()   = -1;
+}
+
+
+inline int Foam::edge::count() const
 {
     label n = 2;
-    if (start() == end() || end() == -1)
+    if (start() == end() || end() < 0)
     {
         --n;
     }
-
-    if (start() == -1)
+    if (start() < 0)
     {
         --n;
     }
@@ -213,15 +319,21 @@ inline Foam::label Foam::edge::count() const
 }
 
 
+inline bool Foam::edge::empty() const
+{
+    return (start() < 0 && end() < 0);
+}
+
+
 inline bool Foam::edge::insert(const label index)
 {
     if (index < 0)
     {
-        // Can never insert invalid point labels.
-        // Use direct assignment for that.
+        // Cannot insert invalid point labels (use direct assignment for that)
         return false;
     }
-    else if (start() == -1)
+
+    if (start() < 0)
     {
         // Store at [0], if not duplicate of [1]
         if (index != end())
@@ -230,7 +342,7 @@ inline bool Foam::edge::insert(const label index)
             return true;
         }
     }
-    else if (end() == -1)
+    else if (end() < 0)
     {
         // Store at [1], if not duplicate of [0]
         if (index != start())
@@ -244,12 +356,29 @@ inline bool Foam::edge::insert(const label index)
 }
 
 
-inline bool Foam::edge::erase(const label index)
+inline int Foam::edge::insert(const UList<label>& lst)
+{
+    return insertMultiple(lst.begin(), lst.end());
+}
+
+template<unsigned AnySize>
+inline int Foam::edge::insert(const FixedList<label, AnySize>& lst)
+{
+    return insertMultiple(lst.begin(), lst.end());
+}
+
+inline int Foam::edge::insert(std::initializer_list<label> lst)
+{
+    return insertMultiple(lst.begin(), lst.end());
+}
+
+
+inline int Foam::edge::erase(const label index)
 {
     if (index < 0)
     {
         // Can never remove invalid point labels!
-        return false;
+        return 0;
     }
 
     int n = 0;
@@ -259,7 +388,7 @@ inline bool Foam::edge::erase(const label index)
         ++n;
     }
 
-    // Automatically handle duplicates, should not have been there anyhow
+    // Automatically handle duplicates, which should not have been there anyhow
     if (index == end())
     {
         end() = -1;
@@ -270,32 +399,24 @@ inline bool Foam::edge::erase(const label index)
 }
 
 
-inline bool Foam::edge::sorted() const
+inline int Foam::edge::erase(const UList<label>& lst)
 {
-    return (start() < end());
+    return eraseMultiple(lst.begin(), lst.end());
 }
 
-
-inline void Foam::edge::sort()
+template<unsigned AnySize>
+inline int Foam::edge::erase(const FixedList<label, AnySize>& lst)
 {
-    if (start() > end())
-    {
-        flip();
-    }
+    return eraseMultiple(lst.begin(), lst.end());
 }
 
-
-inline void Foam::edge::flip()
+inline int Foam::edge::erase(std::initializer_list<label> lst)
 {
-    Swap(operator[](0), operator[](1));
+    return eraseMultiple(lst.begin(), lst.end());
 }
 
 
-inline Foam::edge Foam::edge::reverseEdge() const
-{
-    return edge(end(), start());
-}
-
+// Geometric
 
 inline Foam::point Foam::edge::centre(const UList<point>& pts) const
 {