[geos-commits] [SCM] GEOS branch main updated. d107fccbdffb127af3b571a8f238e700a725984b

git at osgeo.org git at osgeo.org
Thu Sep 23 17:19:42 PDT 2021


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GEOS".

The branch, main has been updated
       via  d107fccbdffb127af3b571a8f238e700a725984b (commit)
       via  c359daa5fa61685be167f6192d84f3f825835bf9 (commit)
      from  32602283fbaf0378f263045e342bd699bb14c735 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit d107fccbdffb127af3b571a8f238e700a725984b
Merge: 3260228 c359daa
Author: Paul Ramsey <pramsey at cleverelephant.ca>
Date:   Thu Sep 23 17:18:55 2021 -0700

    Merge branch 'rouault-fix_queryNode_stack_overflow' into main


commit c359daa5fa61685be167f6192d84f3f825835bf9
Author: Even Rouault <even.rouault at spatialys.com>
Date:   Fri Sep 24 01:22:28 2021 +0200

    KdTree::queryNode(): rewrite it to avoid blowing up the stack
    
    Fixes https://github.com/qgis/QGIS/issues/45226
    
    While we are it, also avoid recursive formulation for queryNodePoint()

diff --git a/src/index/kdtree/KdTree.cpp b/src/index/kdtree/KdTree.cpp
index f22cba6..a0c2dfb 100644
--- a/src/index/kdtree/KdTree.cpp
+++ b/src/index/kdtree/KdTree.cpp
@@ -17,6 +17,7 @@
 
 #include <vector>
 #include <algorithm>
+#include <stack>
 
 using namespace geos::geom;
 
@@ -152,34 +153,76 @@ KdTree::insertExact(const geom::Coordinate& p, void* data)
 void
 KdTree::queryNode(KdNode* currentNode, const geom::Envelope& queryEnv, bool odd, KdNodeVisitor& visitor)
 {
-    if (currentNode == nullptr)
-        return;
-
-    double min;
-    double max;
-    double discriminant;
-
-    if (odd) {
-        min = queryEnv.getMinX();
-        max = queryEnv.getMaxX();
-        discriminant = currentNode->getX();
-    } else {
-        min = queryEnv.getMinY();
-        max = queryEnv.getMaxY();
-        discriminant = currentNode->getY();
-    }
-    bool searchLeft = min < discriminant;
-    bool searchRight = discriminant <= max;
-
-    // search is computed via in-order traversal
-    if (searchLeft) {
-        queryNode(currentNode->getLeft(), queryEnv, !odd, visitor);
-    }
-    if (queryEnv.contains(currentNode->getCoordinate())) {
-        visitor.visit(currentNode);
-    }
-    if (searchRight) {
-        queryNode(currentNode->getRight(), queryEnv, !odd, visitor);
+    // Non recursive formulation of in-order traversal from
+    // http://web.cs.wpi.edu/~cs2005/common/iterative.inorder
+    // Otherwise we may blow up the stack
+    // See https://github.com/qgis/QGIS/issues/45226
+    typedef std::pair<KdNode*, bool> Pair;
+    std::stack<Pair> activeNodes;
+    while(true)
+    {
+        if( currentNode != nullptr )
+        {
+            double min;
+            double discriminant;
+
+            if (odd) {
+                min = queryEnv.getMinX();
+                discriminant = currentNode->getX();
+            } else {
+                min = queryEnv.getMinY();
+                discriminant = currentNode->getY();
+            }
+            bool searchLeft = min < discriminant;
+
+            activeNodes.emplace(Pair(currentNode, odd));
+
+            // search is computed via in-order traversal
+            KdNode* leftNode = nullptr;
+            if (searchLeft ) {
+                leftNode = currentNode->getLeft();
+            }
+            if( leftNode ) {
+                currentNode = leftNode;
+                odd = !odd;
+            } else {
+                currentNode = nullptr;
+            }
+        }
+        else if( !activeNodes.empty() )
+        {
+            currentNode = activeNodes.top().first;
+            odd = activeNodes.top().second;
+            activeNodes.pop();
+
+            if (queryEnv.contains(currentNode->getCoordinate())) {
+                visitor.visit(currentNode);
+            }
+
+            double max;
+            double discriminant;
+
+            if (odd) {
+                max = queryEnv.getMaxX();
+                discriminant = currentNode->getX();
+            } else {
+                max = queryEnv.getMaxY();
+                discriminant = currentNode->getY();
+            }
+            bool searchRight = discriminant <= max;
+
+            if (searchRight) {
+                currentNode = currentNode->getRight();
+                if( currentNode )
+                    odd = !odd;
+            } else {
+                currentNode = nullptr;
+            }
+        }
+        else
+        {
+            break;
+        }
     }
 }
 
@@ -187,29 +230,32 @@ KdTree::queryNode(KdNode* currentNode, const geom::Envelope& queryEnv, bool odd,
 KdNode*
 KdTree::queryNodePoint(KdNode* currentNode, const geom::Coordinate& queryPt, bool odd)
 {
-    if (currentNode == nullptr)
-        return nullptr;
-    if (currentNode->getCoordinate().equals2D(queryPt))
-        return currentNode;
-
-    double ord;
-    double discriminant;
-    if (odd) {
-        ord = queryPt.x;
-        discriminant = currentNode->getX();
-    }
-    else {
-        ord = queryPt.y;
-        discriminant = currentNode->getY();
-    }
+    while (currentNode != nullptr)
+    {
+        if (currentNode->getCoordinate().equals2D(queryPt))
+            return currentNode;
 
-    bool searchLeft = (ord < discriminant);
-    if (searchLeft) {
-        return queryNodePoint(currentNode->getLeft(), queryPt, !odd);
-    }
-    else {
-        return queryNodePoint(currentNode->getRight(), queryPt, !odd);
+        double ord;
+        double discriminant;
+        if (odd) {
+            ord = queryPt.x;
+            discriminant = currentNode->getX();
+        }
+        else {
+            ord = queryPt.y;
+            discriminant = currentNode->getY();
+        }
+
+        bool searchLeft = (ord < discriminant);
+        odd = !odd;
+        if (searchLeft) {
+            currentNode = currentNode->getLeft();
+        }
+        else {
+            currentNode = currentNode->getRight();
+        }
     }
+    return nullptr;
 }
 
 

-----------------------------------------------------------------------

Summary of changes:
 src/index/kdtree/KdTree.cpp | 144 +++++++++++++++++++++++++++++---------------
 1 file changed, 95 insertions(+), 49 deletions(-)


hooks/post-receive
-- 
GEOS


More information about the geos-commits mailing list