From 2a299874cdfec5d04ebb0a0fac01ac92d7b48bc3 Mon Sep 17 00:00:00 2001
From: Stefan Behnel <stefan_ml@behnel.de>
Date: Thu, 9 Apr 2015 20:24:57 +0200
Subject: [PATCH] streamline obj.pop() code

---
 Cython/Compiler/Optimize.py | 16 +++++++--
 Cython/Utility/Optimize.c   | 65 +++++++++++++++++++++++++++----------
 2 files changed, 61 insertions(+), 20 deletions(-)

diff --git a/Cython/Compiler/Optimize.py b/Cython/Compiler/Optimize.py
index 04f4deead..fd0562ef6 100644
--- a/Cython/Compiler/Optimize.py
+++ b/Cython/Compiler/Optimize.py
@@ -2667,7 +2667,8 @@ class OptimizeBuiltinCalls(Visitor.NodeRefCleanupMixin,
     PyObject_PopIndex_func_type = PyrexTypes.CFuncType(
         PyrexTypes.py_object_type, [
             PyrexTypes.CFuncTypeArg("list", PyrexTypes.py_object_type, None),
-            PyrexTypes.CFuncTypeArg("index", PyrexTypes.c_py_ssize_t_type, None),
+            PyrexTypes.CFuncTypeArg("py_index", PyrexTypes.py_object_type, None),
+            PyrexTypes.CFuncTypeArg("c_index", PyrexTypes.c_py_ssize_t_type, None),
             PyrexTypes.CFuncTypeArg("is_signed", PyrexTypes.c_int_type, None),
         ],
         has_varargs=True)  # to fake the additional macro args that lack a proper C type
@@ -2702,14 +2703,23 @@ class OptimizeBuiltinCalls(Visitor.NodeRefCleanupMixin,
             )
         elif len(args) == 2:
             index = unwrap_coerced_node(args[1])
+            py_index = ExprNodes.NoneNode(index.pos)
             orig_index_type = index.type
             if not index.type.is_int:
-                if is_list or isinstance(index, ExprNodes.IntNode):
+                if isinstance(index, ExprNodes.IntNode):
+                    py_index = index.coerce_to_pyobject(self.current_env())
+                    index = index.coerce_to(PyrexTypes.c_py_ssize_t_type, self.current_env())
+                elif is_list:
+                    if index.type.is_pyobject:
+                        py_index = index.coerce_to_simple(self.current_env())
+                        index = ExprNodes.CloneNode(py_index)
                     index = index.coerce_to(PyrexTypes.c_py_ssize_t_type, self.current_env())
                 else:
                     return node
             elif not PyrexTypes.numeric_type_fits(index.type, PyrexTypes.c_py_ssize_t_type):
                 return node
+            elif isinstance(index, ExprNodes.IntNode):
+                py_index = index.coerce_to_pyobject(self.current_env())
             # real type might still be larger at runtime
             if not orig_index_type.is_int:
                 orig_index_type = index.type
@@ -2721,7 +2731,7 @@ class OptimizeBuiltinCalls(Visitor.NodeRefCleanupMixin,
             return ExprNodes.PythonCapiCallNode(
                 node.pos, "__Pyx_Py%s_PopIndex" % type_name,
                 self.PyObject_PopIndex_func_type,
-                args=[obj, index,
+                args=[obj, py_index, index,
                       ExprNodes.IntNode(index.pos, value=str(orig_index_type.signed and 1 or 0),
                                         constant_result=orig_index_type.signed and 1 or 0,
                                         type=PyrexTypes.c_int_type),
diff --git a/Cython/Utility/Optimize.c b/Cython/Utility/Optimize.c
index 2f2aad627..ca0c65eb4 100644
--- a/Cython/Utility/Optimize.c
+++ b/Cython/Utility/Optimize.c
@@ -78,11 +78,17 @@ static CYTHON_INLINE int __Pyx_PyList_Extend(PyObject* L, PyObject* v) {
 
 /////////////// pop.proto ///////////////
 
-#define __Pyx_PyObject_Pop(L) (PyList_CheckExact(L) ? \
-    __Pyx_PyList_Pop(L) : __Pyx__PyObject_Pop(L))
+static CYTHON_INLINE PyObject* __Pyx__PyObject_Pop(PyObject* L); /*proto*/
 
+#if CYTHON_COMPILING_IN_CPYTHON
 static CYTHON_INLINE PyObject* __Pyx_PyList_Pop(PyObject* L); /*proto*/
-static CYTHON_INLINE PyObject* __Pyx__PyObject_Pop(PyObject* L); /*proto*/
+#define __Pyx_PyObject_Pop(L) (likely(PyList_CheckExact(L)) ? \
+    __Pyx_PyList_Pop(L) : __Pyx__PyObject_Pop(L))
+
+#else
+#define __Pyx_PyList_Pop(L)  __Pyx__PyObject_Pop(L)
+#define __Pyx_PyObject_Pop(L)  __Pyx__PyObject_Pop(L)
+#endif
 
 /////////////// pop ///////////////
 //@requires: ObjectHandling.c::PyObjectCallMethod0
@@ -96,44 +102,65 @@ static CYTHON_INLINE PyObject* __Pyx__PyObject_Pop(PyObject* L) {
     return __Pyx_PyObject_CallMethod0(L, PYIDENT("pop"));
 }
 
-static CYTHON_INLINE PyObject* __Pyx_PyList_Pop(PyObject* L) {
 #if CYTHON_COMPILING_IN_CPYTHON
+static CYTHON_INLINE PyObject* __Pyx_PyList_Pop(PyObject* L) {
     /* Check that both the size is positive and no reallocation shrinking needs to be done. */
     if (likely(PyList_GET_SIZE(L) > (((PyListObject*)L)->allocated >> 1))) {
         Py_SIZE(L) -= 1;
         return PyList_GET_ITEM(L, PyList_GET_SIZE(L));
     }
-#endif
     return __Pyx_PyObject_CallMethod0(L, PYIDENT("pop"));
 }
+#endif
 
 
 /////////////// pop_index.proto ///////////////
 
-#define __Pyx_PyObject_PopIndex(L, ix, is_signed, type, to_py_func) ( \
-    (PyList_CheckExact(L) && __Pyx_fits_Py_ssize_t(ix, type, is_signed)) ? \
-        __Pyx__PyList_PopIndex(L, ix) : __Pyx__PyObject_PopIndex(L, to_py_func(ix)))
+static PyObject* __Pyx__PyObject_PopNewIndex(PyObject* L, PyObject* py_ix); /*proto*/
+static PyObject* __Pyx__PyObject_PopIndex(PyObject* L, PyObject* py_ix); /*proto*/
+
+#if CYTHON_COMPILING_IN_CPYTHON
+static PyObject* __Pyx__PyList_PopIndex(PyObject* L, PyObject* py_ix, Py_ssize_t ix); /*proto*/
 
-#define __Pyx_PyList_PopIndex(L, ix, is_signed, type, to_py_func) ( \
+#define __Pyx_PyObject_PopIndex(L, py_ix, ix, is_signed, type, to_py_func) ( \
+    (likely(PyList_CheckExact(L) && __Pyx_fits_Py_ssize_t(ix, type, is_signed))) ? \
+        __Pyx__PyList_PopIndex(L, py_ix, ix) : ( \
+        (unlikely(py_ix == Py_None)) ? __Pyx__PyObject_PopNewIndex(L, to_py_func(ix)) : \
+            __Pyx__PyObject_PopIndex(L, py_ix)))
+
+#define __Pyx_PyList_PopIndex(L, py_ix, ix, is_signed, type, to_py_func) ( \
     __Pyx_fits_Py_ssize_t(ix, type, is_signed) ? \
-        __Pyx__PyList_PopIndex(L, ix) : __Pyx__PyObject_PopIndex(L, to_py_func(ix)))
+        __Pyx__PyList_PopIndex(L, py_ix, ix) : ( \
+        (unlikely(py_ix == Py_None)) ? __Pyx__PyObject_PopNewIndex(L, to_py_func(ix)) : \
+            __Pyx__PyObject_PopIndex(L, py_ix)))
 
-static PyObject* __Pyx__PyList_PopIndex(PyObject* L, Py_ssize_t ix); /*proto*/
-static PyObject* __Pyx__PyObject_PopIndex(PyObject* L, PyObject* py_ix); /*proto*/
+#else
+
+#define __Pyx_PyList_PopIndex(L, py_ix, ix, is_signed, type, to_py_func) \
+    __Pyx_PyObject_PopIndex(L, py_ix, ix, is_signed, type, to_py_func)
+
+#define __Pyx_PyObject_PopIndex(L, py_ix, ix, is_signed, type, to_py_func) ( \
+    (unlikely(py_ix == Py_None)) ? __Pyx__PyObject_PopNewIndex(L, to_py_func(ix)) : \
+        __Pyx__PyObject_PopIndex(L, py_ix))
+#endif
 
 /////////////// pop_index ///////////////
 //@requires: ObjectHandling.c::PyObjectCallMethod1
 
-static PyObject* __Pyx__PyObject_PopIndex(PyObject* L, PyObject* py_ix) {
+static PyObject* __Pyx__PyObject_PopNewIndex(PyObject* L, PyObject* py_ix) {
     PyObject *r;
     if (unlikely(!py_ix)) return NULL;
-    r = __Pyx_PyObject_CallMethod1(L, PYIDENT("pop"), py_ix);
+    r = __Pyx__PyObject_PopIndex(L, py_ix);
     Py_DECREF(py_ix);
     return r;
 }
 
-static PyObject* __Pyx__PyList_PopIndex(PyObject* L, Py_ssize_t ix) {
+static PyObject* __Pyx__PyObject_PopIndex(PyObject* L, PyObject* py_ix) {
+    return __Pyx_PyObject_CallMethod1(L, PYIDENT("pop"), py_ix);
+}
+
 #if CYTHON_COMPILING_IN_CPYTHON
+static PyObject* __Pyx__PyList_PopIndex(PyObject* L, PyObject* py_ix, Py_ssize_t ix) {
     Py_ssize_t size = PyList_GET_SIZE(L);
     if (likely(size > (((PyListObject*)L)->allocated >> 1))) {
         Py_ssize_t cix = ix;
@@ -148,9 +175,13 @@ static PyObject* __Pyx__PyList_PopIndex(PyObject* L, Py_ssize_t ix) {
             return v;
         }
     }
-#endif
-    return __Pyx__PyObject_PopIndex(L, PyInt_FromSsize_t(ix));
+    if (py_ix == Py_None) {
+        return __Pyx__PyObject_PopNewIndex(L, PyInt_FromSsize_t(ix));
+    } else {
+        return __Pyx__PyObject_PopIndex(L, py_ix);
+    }
 }
+#endif
 
 
 /////////////// dict_getitem_default.proto ///////////////
-- 
2.30.9