From eb56c75c4b2f09c9fcf8a76e956641a4b657b048 Mon Sep 17 00:00:00 2001
From: Mark Olesen <Mark.Olesen@esi-group.com>
Date: Tue, 1 Apr 2025 09:02:04 +0200
Subject: [PATCH] ENH: provide edge::sorted() static constructor

- avoids min(a,b), max(a,b) free functions (#3348)
---
 applications/test/edges/Make/files            |  2 +-
 .../edges/{Test-edges.C => Test-edges.cxx}    | 20 ++++++
 .../splitMeshRegions/splitMeshRegions.C       | 24 ++-----
 src/OpenFOAM/meshes/meshShapes/edge/edge.H    | 64 +++++++++++++------
 src/OpenFOAM/meshes/meshShapes/edge/edgeI.H   | 52 +++++++++------
 src/OpenFOAM/primitives/tuples/Pair.H         |  7 --
 .../edgeMesh/edgeFormats/obj/OBJedgeFormat.C  |  3 +-
 src/meshTools/edgeMesh/edgeMesh.C             | 10 +--
 .../multiWorld/multiWorldConnectionsObject.C  |  6 +-
 .../surfaceIntersection/surfaceIntersection.C | 11 ++--
 .../triSurfaceTools/triSurfaceTools.C         |  2 +-
 11 files changed, 118 insertions(+), 83 deletions(-)
 rename applications/test/edges/{Test-edges.C => Test-edges.cxx} (91%)

diff --git a/applications/test/edges/Make/files b/applications/test/edges/Make/files
index 8903c60b8cf..9c6fd4e61e2 100644
--- a/applications/test/edges/Make/files
+++ b/applications/test/edges/Make/files
@@ -1,3 +1,3 @@
-Test-edges.C
+Test-edges.cxx
 
 EXE = $(FOAM_USER_APPBIN)/Test-edges
diff --git a/applications/test/edges/Test-edges.C b/applications/test/edges/Test-edges.cxx
similarity index 91%
rename from applications/test/edges/Test-edges.C
rename to applications/test/edges/Test-edges.cxx
index 43acfbda487..88a580476ed 100644
--- a/applications/test/edges/Test-edges.C
+++ b/applications/test/edges/Test-edges.cxx
@@ -142,6 +142,26 @@ int main(int argc, char *argv[])
     Info<< "sorted ";
     printInfo(e4);
 
+    // Sorted construction
+    {
+        edge edge1(10, 5);
+
+        Info<< "plain ";
+        printInfo(edge1);
+
+        // construct sorted
+        auto edge3(edge::sorted(10, 5));
+
+        Info<< "sorted ";
+        printInfo(edge3);
+
+        // // construct sorted (deprecated)
+        // edge edge2(10, 5, true);
+        //
+        // Info<< "sorted ";
+        // printInfo(edge2);
+    }
+
     return 0;
 }
 
diff --git a/applications/utilities/mesh/manipulation/splitMeshRegions/splitMeshRegions.C b/applications/utilities/mesh/manipulation/splitMeshRegions/splitMeshRegions.C
index ae9d91f0b19..232acc23be0 100644
--- a/applications/utilities/mesh/manipulation/splitMeshRegions/splitMeshRegions.C
+++ b/applications/utilities/mesh/manipulation/splitMeshRegions/splitMeshRegions.C
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2017 OpenFOAM Foundation
-    Copyright (C) 2015-2024 OpenCFD Ltd.
+    Copyright (C) 2015-2025 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -269,11 +269,7 @@ void addToInterface
     EdgeMap<Map<label>>& regionsToSize
 )
 {
-    edge interface
-    (
-        min(ownRegion, neiRegion),
-        max(ownRegion, neiRegion)
-    );
+    const auto interface(edge::sorted(ownRegion, neiRegion));
 
     auto iter = regionsToSize.find(interface);
 
@@ -503,18 +499,14 @@ void getInterfaceSizes
 
         if (ownRegion != neiRegion)
         {
+            const auto interface(edge::sorted(ownRegion, neiRegion));
+
             label zoneID = -1;
             if (useFaceZones)
             {
                 zoneID = mesh.faceZones().whichZone(facei);
             }
 
-            edge interface
-            (
-                min(ownRegion, neiRegion),
-                max(ownRegion, neiRegion)
-            );
-
             faceToInterface[facei] = regionsToInterface[interface][zoneID];
         }
     }
@@ -526,18 +518,14 @@ void getInterfaceSizes
 
         if (ownRegion != neiRegion)
         {
+            const auto interface(edge::sorted(ownRegion, neiRegion));
+
             label zoneID = -1;
             if (useFaceZones)
             {
                 zoneID = mesh.faceZones().whichZone(facei);
             }
 
-            edge interface
-            (
-                min(ownRegion, neiRegion),
-                max(ownRegion, neiRegion)
-            );
-
             faceToInterface[facei] = regionsToInterface[interface][zoneID];
         }
     }
diff --git a/src/OpenFOAM/meshes/meshShapes/edge/edge.H b/src/OpenFOAM/meshes/meshShapes/edge/edge.H
index c479af22171..a9c2f61ccec 100644
--- a/src/OpenFOAM/meshes/meshShapes/edge/edge.H
+++ b/src/OpenFOAM/meshes/meshShapes/edge/edge.H
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2015 OpenFOAM Foundation
-    Copyright (C) 2017-2023 OpenCFD Ltd.
+    Copyright (C) 2017-2025 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -79,19 +79,13 @@ public:
         inline edge();
 
         //- Construct from two vertex labels
-        inline edge(const label from, const label to);
+        inline edge(label from, label to);
 
-        //- Construct from pair of vertex labels
+        //- Construct from two vertex labels
         inline edge(const labelPair& pair);
 
-        //- Construct from list of vertex labels
-        inline edge(const FixedList<label, 2>& list);
-
-        //- Construct from two vertex labels, sorted with first less-than second
-        inline edge(const label from, const label to, const bool doSort);
-
-        //- Construct from list, sorted with first less-than second
-        inline edge(const FixedList<label, 2>& list, const bool doSort);
+        //- Construct from two vertex labels
+        inline edge(const FixedList<label, 2>& pair);
 
         //- Copy construct from a subset of vertex labels
         inline edge
@@ -104,6 +98,18 @@ public:
         inline edge(Istream& is);
 
 
+    // Static Functions
+
+        //- Create (in ascending order) from two vertex labels
+        inline static edge sorted(label from, label to);
+
+        //- Create (in ascending order) from two vertex labels
+        inline static edge sorted(const labelPair& pair);
+
+        //- Create (in ascending order) from two vertex labels
+        inline static edge sorted(const FixedList<label, 2>& pair);
+
+
     // Member Functions
 
     // Access
@@ -111,27 +117,27 @@ public:
         //- The first vertex
         label a() const noexcept { return labelPair::first(); }
 
-        //- The second vertex
-        label b() const noexcept { return labelPair::second(); }
-
         //- The first vertex
         label& a() noexcept { return labelPair::first(); }
 
+        //- The second vertex
+        label b() const noexcept { return labelPair::second(); }
+
         //- The second vertex
         label& b() noexcept { return labelPair::second(); }
 
         //- The start (first) vertex label
         label start() const noexcept { return labelPair::first(); }
 
-        //- The end (last/second) vertex label
-        label end() const noexcept { return labelPair::second(); }
-
         //- The start (first) vertex label
         label& start() noexcept { return labelPair::first(); }
 
         //- The end (second/last) vertex label
         label& end() noexcept { return labelPair::second(); }
 
+        //- The end (last/second) vertex label
+        label end() const noexcept { return labelPair::second(); }
+
 
         //- Return reverse edge as copy.
         //  No special handling of negative vertex labels.
@@ -142,11 +148,11 @@ public:
 
         //- Return the smallest vertex label used by the edge
         //  No special handling of negative vertex labels.
-        inline label minVertex() const noexcept;
+        inline label min() const noexcept;
 
         //- Return the largest vertex label used by the edge
         //  No special handling of negative vertex labels.
-        inline label maxVertex() const noexcept;
+        inline label max() const noexcept;
 
         //- True if the vertices are unique and non-negative.
         inline bool good() const noexcept;
@@ -328,12 +334,32 @@ public:
 
     // Housekeeping
 
+        //- Construct from two vertex labels, sorted with first less-than second
+        FOAM_DEPRECATED_FOR(2025-04, "edge::sorted() factory")
+        edge(label from, label to, bool doSort) : labelPair(from, to)
+        {
+            if (doSort) labelPair::sort();
+        }
+
+        //- Construct from list, sorted with first less-than second
+        FOAM_DEPRECATED_FOR(2025-04, "edge::sorted() factory")
+        edge(const FixedList<label, 2>& pair, bool doSort) : labelPair(pair)
+        {
+            if (doSort) labelPair::sort();
+        }
+
         //- Same as contains()
         bool found(label vertex) const { return contains(vertex); }
 
         //- Same as good()
         bool valid() const noexcept { return good(); }
 
+        //- Same as min()
+        label minVert() const noexcept { return edge::min(); }
+
+        //- Same as max()
+        label maxVert() const noexcept { return edge::max(); }
+
         //- Deprecated(2021-04) hashing functor. Use hasher()
         // \deprecated(2021-04) - use hasher() functor
         template<class Unused=bool>
diff --git a/src/OpenFOAM/meshes/meshShapes/edge/edgeI.H b/src/OpenFOAM/meshes/meshShapes/edge/edgeI.H
index 4ac3fa4ca22..2bc39f7b81f 100644
--- a/src/OpenFOAM/meshes/meshShapes/edge/edgeI.H
+++ b/src/OpenFOAM/meshes/meshShapes/edge/edgeI.H
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011 OpenFOAM Foundation
-    Copyright (C) 2017-2023 OpenCFD Ltd.
+    Copyright (C) 2017-2025 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -36,6 +36,34 @@ inline int Foam::edge::compare(const edge& a, const edge& b)
 }
 
 
+inline Foam::edge Foam::edge::sorted(label from, label to)
+{
+    return (from < to) ? edge(from, to) : edge(to, from);
+}
+
+
+inline Foam::edge Foam::edge::sorted(const labelPair& pair)
+{
+    return
+    (
+        pair.first() < pair.second()
+      ? edge(pair.first(), pair.second())
+      : edge(pair.second(), pair.first())
+    );
+}
+
+
+inline Foam::edge Foam::edge::sorted(const FixedList<label, 2>& pair)
+{
+    return
+    (
+        (pair.get<0>() < pair.get<1>())
+      ? edge(pair.get<0>(), pair.get<1>())
+      : edge(pair.get<1>(), pair.get<0>())
+    );
+}
+
+
 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
 
 inline Foam::edge::edge()
@@ -44,7 +72,7 @@ inline Foam::edge::edge()
 {}
 
 
-inline Foam::edge::edge(const label from, const label to)
+inline Foam::edge::edge(label from, label to)
 :
     labelPair(from, to)
 {}
@@ -56,21 +84,9 @@ inline Foam::edge::edge(const labelPair& pair)
 {}
 
 
-inline Foam::edge::edge(const FixedList<label, 2>& list)
-:
-    labelPair(list.get<0>(), list.get<1>())
-{}
-
-
-inline Foam::edge::edge(const label from, const label to, const bool doSort)
-:
-    labelPair(from, to, doSort)
-{}
-
-
-inline Foam::edge::edge(const FixedList<label, 2>& list, const bool doSort)
+inline Foam::edge::edge(const FixedList<label, 2>& pair)
 :
-    labelPair(list, doSort)
+    labelPair(pair.get<0>(), pair.get<1>())
 {}
 
 
@@ -92,13 +108,13 @@ inline Foam::edge::edge(Istream& is)
 
 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
 
-inline Foam::label Foam::edge::minVertex() const noexcept
+inline Foam::label Foam::edge::min() const noexcept
 {
     return (first() < second() ? first() : second());
 }
 
 
-inline Foam::label Foam::edge::maxVertex() const noexcept
+inline Foam::label Foam::edge::max() const noexcept
 {
     return (second() < first() ? first() : second());
 }
diff --git a/src/OpenFOAM/primitives/tuples/Pair.H b/src/OpenFOAM/primitives/tuples/Pair.H
index c3845c9951c..add3bf558ce 100644
--- a/src/OpenFOAM/primitives/tuples/Pair.H
+++ b/src/OpenFOAM/primitives/tuples/Pair.H
@@ -174,13 +174,6 @@ public:
                 }
             }
         };
-
-
-    // Housekeeping
-
-        //- Deprecated(2023-07) Use is_sorted() method
-        //  \deprecated(2023-07) Use is_sorted() method
-        bool sorted() const { return is_sorted(); }
 };
 
 
diff --git a/src/meshTools/edgeMesh/edgeFormats/obj/OBJedgeFormat.C b/src/meshTools/edgeMesh/edgeFormats/obj/OBJedgeFormat.C
index b184cab6211..51bc85de8ff 100644
--- a/src/meshTools/edgeMesh/edgeFormats/obj/OBJedgeFormat.C
+++ b/src/meshTools/edgeMesh/edgeFormats/obj/OBJedgeFormat.C
@@ -215,8 +215,7 @@ bool Foam::fileFormats::OBJedgeFormat::read(const fileName& filename)
     {
         for (edge& e : dynEdges)
         {
-            e[0] = dynUsedPoints[e[0]];
-            e[1] = dynUsedPoints[e[1]];
+            e = edge(dynUsedPoints, e);
         }
     }
     storedEdges().transfer(dynEdges);
diff --git a/src/meshTools/edgeMesh/edgeMesh.C b/src/meshTools/edgeMesh/edgeMesh.C
index 1f0ea0d2d51..fe491732b55 100644
--- a/src/meshTools/edgeMesh/edgeMesh.C
+++ b/src/meshTools/edgeMesh/edgeMesh.C
@@ -230,8 +230,7 @@ void Foam::edgeMesh::mergePoints(const scalar mergeDist)
 
         for (edge& e : edges_)
         {
-            e[0] = pointMap[e[0]];
-            e[1] = pointMap[e[1]];
+            e = edge(pointMap, e);
         }
     }
 
@@ -314,12 +313,9 @@ void Foam::edgeMesh::mergeEdges()
         points_.setSize(newId);
 
         // Renumber edges - already sorted (above)
-        forAll(edges_, edgeI)
+        for (edge& e : edges_)
         {
-            edge& e = edges_[edgeI];
-
-            e[0] = pointMap[e[0]];
-            e[1] = pointMap[e[1]];
+            e = edge(pointMap, e);
         }
     }
 }
diff --git a/src/meshTools/multiWorld/multiWorldConnectionsObject.C b/src/meshTools/multiWorld/multiWorldConnectionsObject.C
index d10def44641..4618bed21cc 100644
--- a/src/meshTools/multiWorld/multiWorldConnectionsObject.C
+++ b/src/meshTools/multiWorld/multiWorldConnectionsObject.C
@@ -5,7 +5,7 @@
     \\  /    A nd           | www.openfoam.com
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
-    Copyright (C) 2021-2023 OpenCFD Ltd.
+    Copyright (C) 2021-2025 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -112,7 +112,7 @@ Foam::edge Foam::multiWorldConnections::worldPair(const label otherWorld)
     const label thisWorldID = UPstream::myWorldID();
 
     // The worlds (sorted)
-    return edge(thisWorldID, otherWorld, true);
+    return edge::sorted(thisWorldID, otherWorld);
 }
 
 
@@ -136,7 +136,7 @@ Foam::edge Foam::multiWorldConnections::worldPair(const word& otherWorld)
     }
 
     // The worlds (sorted)
-    return edge(thisWorldID, otherWorldID, true);
+    return edge::sorted(thisWorldID, otherWorldID);
 }
 
 
diff --git a/src/meshTools/triSurface/booleanOps/surfaceIntersection/surfaceIntersection.C b/src/meshTools/triSurface/booleanOps/surfaceIntersection/surfaceIntersection.C
index 4a9115417f7..3e47664ac5a 100644
--- a/src/meshTools/triSurface/booleanOps/surfaceIntersection/surfaceIntersection.C
+++ b/src/meshTools/triSurface/booleanOps/surfaceIntersection/surfaceIntersection.C
@@ -989,8 +989,8 @@ void Foam::surfaceIntersection::joinDisconnected
 
         if (e.count() == 1)
         {
-            // minVertex = -1 (unused), maxVertex = pointId
-            const label pointId = e.maxVertex();
+            // min vertex = -1 (unused), max vertex = pointId
+            const label pointId = e.max();
 
             missedFacePoint[0](twoFaces[0]).insert
             (
@@ -1498,12 +1498,9 @@ void Foam::surfaceIntersection::mergePoints(const scalar mergeDist)
 
     if (nChanged)
     {
-        forAll(cutEdges_, edgei)
+        for (edge& e : cutEdges_)
         {
-            edge& e = cutEdges_[edgei];
-
-            e[0] = pointMap[e[0]];
-            e[1] = pointMap[e[1]];
+            e = edge(pointMap, e);
         }
 
         forAll(surf1EdgeCuts_, edgei)
diff --git a/src/meshTools/triSurface/triSurfaceTools/triSurfaceTools.C b/src/meshTools/triSurface/triSurfaceTools/triSurfaceTools.C
index ac7636832ac..c436b14e5ce 100644
--- a/src/meshTools/triSurface/triSurfaceTools/triSurfaceTools.C
+++ b/src/meshTools/triSurface/triSurfaceTools/triSurfaceTools.C
@@ -1636,7 +1636,7 @@ Foam::triSurface Foam::triSurfaceTools::collapseEdges
                         << abort(FatalError);
                 }
 
-                const label minVert = min(e.start(), e.end());
+                const label minVert = e.min();
                 pointMap[e.start()] = minVert;
                 pointMap[e.end()] = minVert;
 
-- 
GitLab