diff --git a/src/pugixml.cpp b/src/pugixml.cpp
index 94073f3b0f223cc06a28f3aa2bb265cc5563d9ac..8417c44f7ae9cbb39bb5b63d6ae5303664109ad3 100644
--- a/src/pugixml.cpp
+++ b/src/pugixml.cpp
@@ -6808,44 +6808,71 @@ PUGI__NS_BEGIN
 		}
 	}
 	
-	PUGI__FN unsigned int node_height(xml_node n)
+	PUGI__FN bool node_is_before_sibling(xml_node_struct* ln, xml_node_struct* rn)
 	{
-		unsigned int result = 0;
-		
-		while (n)
+		assert(ln->parent == rn->parent);
+
+		// there is no common ancestor (the shared parent is null), nodes are from different documents
+		if (!ln->parent) return ln < rn;
+
+		// determine sibling order
+		xml_node_struct* ls = ln;
+		xml_node_struct* rs = rn;
+
+		while (ls && rs)
 		{
-			++result;
-			n = n.parent();
+			if (ls == rn) return true;
+			if (rs == ln) return false;
+
+			ls = ls->next_sibling;
+			rs = rs->next_sibling;
 		}
-		
-		return result;
+
+		// if rn sibling chain ended ln must be before rn
+		return !rs;
 	}
 	
-	PUGI__FN bool node_is_before(xml_node ln, unsigned int lh, xml_node rn, unsigned int rh)
+	PUGI__FN bool node_is_before(xml_node_struct* ln, xml_node_struct* rn)
 	{
-		// normalize heights
-		for (unsigned int i = rh; i < lh; i++) ln = ln.parent();
-		for (unsigned int j = lh; j < rh; j++) rn = rn.parent();
-		
-		// one node is the ancestor of the other
-		if (ln == rn) return lh < rh;
-		
-		// find common ancestor
-		while (ln.parent() != rn.parent())
+		// find common ancestor at the same depth, if any
+		xml_node_struct* lp = ln;
+		xml_node_struct* rp = rn;
+
+		while (lp && rp && lp->parent != rp->parent)
 		{
-			ln = ln.parent();
-			rn = rn.parent();
+			lp = lp->parent;
+			rp = rp->parent;
 		}
 
-		// there is no common ancestor (the shared parent is null), nodes are from different documents
-		if (!ln.parent()) return ln < rn;
+		// parents are the same!
+		if (lp && rp) return node_is_before_sibling(lp, rp);
 
-		// determine sibling order
-		for (; ln; ln = ln.next_sibling())
-			if (ln == rn)
-				return true;
+		// nodes are at different depths, need to normalize heights
+		bool left_higher = !lp;
 
-		return false;
+		while (lp)
+		{
+			lp = lp->parent;
+			ln = ln->parent;
+		}
+
+		while (rp)
+		{
+			rp = rp->parent;
+			rn = rn->parent;
+		}
+
+		// one node is the ancestor of the other
+		if (ln == rn) return left_higher;
+
+		// find common ancestor... again
+		while (ln->parent != rn->parent)
+		{
+			ln = ln->parent;
+			rn = rn->parent;
+		}
+
+		return node_is_before_sibling(ln, rn);
 	}
 
 	PUGI__FN bool node_is_ancestor(xml_node parent, xml_node node)
@@ -6933,11 +6960,10 @@ PUGI__NS_BEGIN
 			}
 
 			if (ln == rn) return false;
+
+			if (!ln || !rn) return ln < rn;
 			
-			unsigned int lh = node_height(ln);
-			unsigned int rh = node_height(rn);
-			
-			return node_is_before(ln, lh, rn, rh);
+			return node_is_before(ln.internal_object(), rn.internal_object());
 		}
 	};