Patchwork [3,of,4] dirs: port PyInt code to work on Python 3

login
register
mail settings
Submitter Gregory Szorc
Date Oct. 8, 2016, 3 p.m.
Message ID <da39a5835ea2d1aae1a5.1475938847@gps-mbp.local>
Download mbox | patch
Permalink /patch/16927/
State Accepted
Headers show

Comments

Gregory Szorc - Oct. 8, 2016, 3 p.m.
# HG changeset patch
# User Gregory Szorc <gregory.szorc@gmail.com>
# Date 1475936421 -7200
#      Sat Oct 08 16:20:21 2016 +0200
# Node ID da39a5835ea2d1aae1a51995b6d7e593f598be4b
# Parent  3904cbad91663a7ae74c117a21879220b3e851b6
dirs: port PyInt code to work on Python 3

PyIntObject no longer exists in Python 3. Instead, there is
PyLongObject.

Furthermore, PyInt_AS_LONG is a macro referencing a struct member.
PyInt_AS_LONG doesn't exist in Python 3 and PyLong_AS_LONG is a
#define for PyLong_AsLong, which is a function. So assigning to the
return value of PyLong_AS_LONG doesn't work.

This patch introduces a macro for obtaining the value of an
integer-like type that works on Python 2 and Python 3. On
Python 3, we access the struct field of the underlying
PyLongObjet directly, without overflow checking. This is
essentially the same as what Python 2 was doing except using a
PyLong instead of a PyInt.

Patch

diff --git a/mercurial/dirs.c b/mercurial/dirs.c
--- a/mercurial/dirs.c
+++ b/mercurial/dirs.c
@@ -10,8 +10,18 @@ 
 #define PY_SSIZE_T_CLEAN
 #include <Python.h>
 #include "util.h"
 
+#if PY_MAJOR_VERSION >= 3
+#define IS_PY3K
+#endif
+
+#ifdef IS_PY3K
+#define PYLONG_VALUE(o) ((PyLongObject *)o)->ob_digit[1]
+#else
+#define PYLONG_VALUE(o) PyInt_AS_LONG(o)
+#endif
+
 /*
  * This is a multiset of directory names, built from the files that
  * appear in a dirstate or manifest.
  *
@@ -65,19 +75,23 @@  static int _addpath(PyObject *dirs, PyOb
 		((PyBytesObject *)key)->ob_sval[pos] = '\0';
 
 		val = PyDict_GetItem(dirs, key);
 		if (val != NULL) {
-			PyInt_AS_LONG(val) += 1;
+			PYLONG_VALUE(val) += 1;
 			break;
 		}
 
 		/* Force Python to not reuse a small shared int. */
+#ifdef IS_PY3K
+		val = PyLong_FromLong(0x1eadbeef);
+#else
 		val = PyInt_FromLong(0x1eadbeef);
+#endif
 
 		if (val == NULL)
 			goto bail;
 
-		PyInt_AS_LONG(val) = 1;
+		PYLONG_VALUE(val) = 1;
 		ret = PyDict_SetItem(dirs, key, val);
 		Py_DECREF(val);
 		if (ret == -1)
 			goto bail;
@@ -112,9 +126,9 @@  static int _delpath(PyObject *dirs, PyOb
 					"expected a value, found none");
 			goto bail;
 		}
 
-		if (--PyInt_AS_LONG(val) <= 0) {
+		if (--PYLONG_VALUE(val) <= 0) {
 			if (PyDict_DelItem(dirs, key) == -1)
 				goto bail;
 		} else
 			break;