changeset 25015:b3a68fb8b859

dirs: back out forward-searching in finddirs() This backs out the changes below. The next patch will implement a faster algorithm based on backward-walking in finddirs(). 67241ee427cf (dirs._addpath: reinstate use of Py_CLEAR, 2015-04-07) 6f0e6fa9fdd7 (dirs._addpath: don't mutate Python strings after exposing them (issue4589), 2015-04-06) 1a9efc312700 (dirs.addpath: rework algorithm to search forward, 2015-03-27)
author Martin von Zweigbergk <martinvonz@google.com>
date Fri, 08 May 2015 15:09:28 -0700
parents 7e5d5160073b
children 42e89b87ca79
files mercurial/dirs.c
diffstat 1 files changed, 16 insertions(+), 28 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/dirs.c	Wed Apr 15 08:19:36 2015 -0700
+++ b/mercurial/dirs.c	Fri May 08 15:09:28 2015 -0700
@@ -9,7 +9,6 @@
 
 #define PY_SSIZE_T_CLEAN
 #include <Python.h>
-#include <string.h>
 #include "util.h"
 
 /*
@@ -33,19 +32,23 @@
 {
 	const char *s = PyString_AS_STRING(path);
 
-	const char *ret = strchr(s + pos, '/');
-	return (ret != NULL) ? (ret - s) : -1;
+	while (pos != -1) {
+		if (s[pos] == '/')
+			break;
+		pos -= 1;
+	}
+
+	return pos;
 }
 
 static int _addpath(PyObject *dirs, PyObject *path)
 {
-	char *cpath = PyString_AS_STRING(path);
-	Py_ssize_t len = PyString_GET_SIZE(path);
-	Py_ssize_t pos = -1;
+	const char *cpath = PyString_AS_STRING(path);
+	Py_ssize_t pos = PyString_GET_SIZE(path);
 	PyObject *key = NULL;
 	int ret = -1;
 
-	while ((pos = _finddir(path, pos + 1)) != -1) {
+	while ((pos = _finddir(path, pos - 1)) != -1) {
 		PyObject *val;
 
 		/* It's likely that every prefix already has an entry
@@ -53,18 +56,10 @@
 		   deallocating a string for each prefix we check. */
 		if (key != NULL)
 			((PyStringObject *)key)->ob_shash = -1;
-		else if (pos != 0) {
-			/* pos >= 1, which means that len >= 2. This is
-			   guaranteed to produce a non-interned string. */
-			key = PyString_FromStringAndSize(cpath, len);
-			if (key == NULL)
-				goto bail;
-		} else {
-			/* pos == 0, which means we need to increment the dir
-			   count for the empty string. We need to make sure we
-			   don't muck around with interned strings, so throw it
-			   away later. */
-			key = PyString_FromString("");
+		else {
+			/* Force Python to not reuse a small shared string. */
+			key = PyString_FromStringAndSize(cpath,
+							 pos < 2 ? 2 : pos);
 			if (key == NULL)
 				goto bail;
 		}
@@ -74,10 +69,6 @@
 		val = PyDict_GetItem(dirs, key);
 		if (val != NULL) {
 			PyInt_AS_LONG(val) += 1;
-			if (pos != 0)
-				PyString_AS_STRING(key)[pos] = '/';
-			else
-				key = NULL;
 			continue;
 		}
 
@@ -92,9 +83,6 @@
 		Py_DECREF(val);
 		if (ret == -1)
 			goto bail;
-
-		/* Clear the key out since we've already exposed it to Python
-		   and can't mutate it further. */
 		Py_CLEAR(key);
 	}
 	ret = 0;
@@ -107,11 +95,11 @@
 
 static int _delpath(PyObject *dirs, PyObject *path)
 {
-	Py_ssize_t pos = -1;
+	Py_ssize_t pos = PyString_GET_SIZE(path);
 	PyObject *key = NULL;
 	int ret = -1;
 
-	while ((pos = _finddir(path, pos + 1)) != -1) {
+	while ((pos = _finddir(path, pos - 1)) != -1) {
 		PyObject *val;
 
 		key = PyString_FromStringAndSize(PyString_AS_STRING(path), pos);