cython-devel
changeset 2653:2e3dda4a7d23
Optimized list pop.
| author | Robert Bradshaw <robertwb@math.washington.edu> |
|---|---|
| date | Tue Nov 03 01:01:54 2009 -0800 (2 years ago) |
| parents | 9e89fd2338d8 |
| children | 76e7121cbdc7 |
| files | Cython/Compiler/Optimize.py tests/run/list_pop.pyx |
line diff
1.1 --- a/Cython/Compiler/Optimize.py Tue Nov 03 00:56:50 2009 -0800
1.2 +++ b/Cython/Compiler/Optimize.py Tue Nov 03 01:01:54 2009 -0800
1.3 @@ -1104,6 +1104,40 @@
1.4 utility_code = append_utility_code
1.5 )
1.6
1.7 + PyObject_Pop_func_type = PyrexTypes.CFuncType(
1.8 + PyrexTypes.py_object_type, [
1.9 + PyrexTypes.CFuncTypeArg("list", PyrexTypes.py_object_type, None),
1.10 + ])
1.11 +
1.12 + PyObject_PopIndex_func_type = PyrexTypes.CFuncType(
1.13 + PyrexTypes.py_object_type, [
1.14 + PyrexTypes.CFuncTypeArg("list", PyrexTypes.py_object_type, None),
1.15 + PyrexTypes.CFuncTypeArg("index", PyrexTypes.c_long_type, None),
1.16 + ])
1.17 +
1.18 + def _handle_simple_method_object_pop(self, node, args, is_unbound_method):
1.19 + # X.pop([n]) is almost always referring to a list
1.20 + if len(args) == 1:
1.21 + return ExprNodes.PythonCapiCallNode(
1.22 + node.pos, "__Pyx_PyObject_Pop", self.PyObject_Pop_func_type,
1.23 + args = args,
1.24 + is_temp = node.is_temp,
1.25 + utility_code = pop_utility_code
1.26 + )
1.27 + elif len(args) == 2:
1.28 + if isinstance(args[1], ExprNodes.CoerceToPyTypeNode) and args[1].arg.type.is_int:
1.29 + original_type = args[1].arg.type
1.30 + if PyrexTypes.widest_numeric_type(original_type, PyrexTypes.c_py_ssize_t_type) == PyrexTypes.c_py_ssize_t_type:
1.31 + args[1] = args[1].arg
1.32 + return ExprNodes.PythonCapiCallNode(
1.33 + node.pos, "__Pyx_PyObject_PopIndex", self.PyObject_PopIndex_func_type,
1.34 + args = args,
1.35 + is_temp = node.is_temp,
1.36 + utility_code = pop_index_utility_code
1.37 + )
1.38 +
1.39 + return node
1.40 +
1.41 PyList_Append_func_type = PyrexTypes.CFuncType(
1.42 PyrexTypes.c_int_type, [
1.43 PyrexTypes.CFuncTypeArg("list", PyrexTypes.py_object_type, None),
1.44 @@ -1360,6 +1394,76 @@
1.45 )
1.46
1.47
1.48 +pop_utility_code = UtilityCode(
1.49 +proto = """
1.50 +static INLINE PyObject* __Pyx_PyObject_Pop(PyObject* L) {
1.51 + if (likely(PyList_CheckExact(L))
1.52 + /* Check that both the size is positive and no reallocation shrinking needs to be done. */
1.53 + && likely(PyList_GET_SIZE(L) > (((PyListObject*)L)->allocated >> 1))) {
1.54 + Py_SIZE(L) -= 1;
1.55 + return PyList_GET_ITEM(L, PyList_GET_SIZE(L));
1.56 + }
1.57 + else {
1.58 + PyObject *r, *m;
1.59 + m = __Pyx_GetAttrString(L, "pop");
1.60 + if (!m) return NULL;
1.61 + r = PyObject_CallObject(m, NULL);
1.62 + Py_DECREF(m);
1.63 + return r;
1.64 + }
1.65 +}
1.66 +""",
1.67 +impl = ""
1.68 +)
1.69 +
1.70 +pop_index_utility_code = UtilityCode(
1.71 +proto = """
1.72 +static PyObject* __Pyx_PyObject_PopIndex(PyObject* L, Py_ssize_t ix);
1.73 +""",
1.74 +impl = """
1.75 +static PyObject* __Pyx_PyObject_PopIndex(PyObject* L, Py_ssize_t ix) {
1.76 + PyObject *r, *m, *t, *py_ix;
1.77 + if (likely(PyList_CheckExact(L))) {
1.78 + Py_ssize_t size = PyList_GET_SIZE(L);
1.79 + if (likely(size > (((PyListObject*)L)->allocated >> 1))) {
1.80 + if (ix < 0) {
1.81 + ix += size;
1.82 + }
1.83 + if (likely(0 <= ix && ix < size)) {
1.84 + Py_ssize_t i;
1.85 + PyObject* v = PyList_GET_ITEM(L, ix);
1.86 + Py_SIZE(L) -= 1;
1.87 + size -= 1;
1.88 + for(i=ix; i<size; i++) {
1.89 + PyList_SET_ITEM(L, i, PyList_GET_ITEM(L, i+1));
1.90 + }
1.91 + return v;
1.92 + }
1.93 + }
1.94 + }
1.95 + py_ix = t = NULL;
1.96 + m = __Pyx_GetAttrString(L, "pop");
1.97 + if (!m) goto bad;
1.98 + py_ix = PyInt_FromSsize_t(ix);
1.99 + if (!py_ix) goto bad;
1.100 + t = PyTuple_New(1);
1.101 + if (!t) goto bad;
1.102 + PyTuple_SET_ITEM(t, 0, py_ix);
1.103 + py_ix = NULL;
1.104 + r = PyObject_CallObject(m, t);
1.105 + Py_DECREF(m);
1.106 + Py_DECREF(t);
1.107 + return r;
1.108 +bad:
1.109 + Py_XDECREF(m);
1.110 + Py_XDECREF(t);
1.111 + Py_XDECREF(py_ix);
1.112 + return NULL;
1.113 +}
1.114 +"""
1.115 +)
1.116 +
1.117 +
1.118 pytype_utility_code = UtilityCode(
1.119 proto = """
1.120 static INLINE PyObject* __Pyx_Type(PyObject* o) {
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2.2 +++ b/tests/run/list_pop.pyx Tue Nov 03 01:01:54 2009 -0800
2.3 @@ -0,0 +1,81 @@
2.4 +cimport cython
2.5 +
2.6 +class A:
2.7 + def pop(self, *args):
2.8 + print args
2.9 + return None
2.10 +
2.11 +
2.12 +@cython.test_assert_path_exists('//PythonCapiCallNode')
2.13 +@cython.test_fail_if_path_exists('//SimpleCallNode/AttributeNode')
2.14 +def simple_pop(L):
2.15 + """
2.16 + >>> L = range(10)
2.17 + >>> simple_pop(L)
2.18 + 9
2.19 + >>> simple_pop(L)
2.20 + 8
2.21 + >>> L
2.22 + [0, 1, 2, 3, 4, 5, 6, 7]
2.23 + >>> while L:
2.24 + ... _ = simple_pop(L)
2.25 +
2.26 + >>> L
2.27 + []
2.28 + >>> simple_pop(L)
2.29 + Traceback (most recent call last):
2.30 + ...
2.31 + IndexError: pop from empty list
2.32 +
2.33 + >>> simple_pop(A())
2.34 + ()
2.35 + """
2.36 + return L.pop()
2.37 +
2.38 +@cython.test_assert_path_exists('//PythonCapiCallNode')
2.39 +@cython.test_fail_if_path_exists('//SimpleCallNode/AttributeNode')
2.40 +def index_pop(L, int i):
2.41 + """
2.42 + >>> L = range(10)
2.43 + >>> index_pop(L, 2)
2.44 + 2
2.45 + >>> index_pop(L, -2)
2.46 + 8
2.47 + >>> L
2.48 + [0, 1, 3, 4, 5, 6, 7, 9]
2.49 + >>> index_pop(L, 100)
2.50 + Traceback (most recent call last):
2.51 + ...
2.52 + IndexError: pop index out of range
2.53 + >>> index_pop(L, -100)
2.54 + Traceback (most recent call last):
2.55 + ...
2.56 + IndexError: pop index out of range
2.57 +
2.58 + >>> while L:
2.59 + ... _ = index_pop(L, 0)
2.60 +
2.61 + >>> L
2.62 + []
2.63 +
2.64 + >>> index_pop(L, 0)
2.65 + Traceback (most recent call last):
2.66 + ...
2.67 + IndexError: pop from empty list
2.68 +
2.69 + >>> index_pop(A(), 3)
2.70 + (3,)
2.71 + """
2.72 + return L.pop(i)
2.73 +
2.74 +@cython.test_fail_if_path_exists('//PythonCapiCallNode')
2.75 +def crazy_pop(L):
2.76 + """
2.77 + >>> crazy_pop(range(10))
2.78 + Traceback (most recent call last):
2.79 + ...
2.80 + TypeError: pop() takes at most 1 argument (3 given)
2.81 + >>> crazy_pop(A())
2.82 + (1, 2, 3)
2.83 + """
2.84 + return L.pop(1, 2, 3)
