Author: Armin Rigo <[email protected]>
Branch: slicing
Changeset: r1134:b68c5dd2b9ce
Date: 2013-02-10 14:44 +0100
http://bitbucket.org/cffi/cffi/changeset/b68c5dd2b9ce/

Log:    getting a slice

diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c
--- a/c/_cffi_backend.c
+++ b/c/_cffi_backend.c
@@ -102,7 +102,8 @@
     PyObject *ct_stuff;                /* structs: dict of the fields
                                           arrays: ctypedescr of the ptr type
                                           function: tuple(abi, ctres, ctargs..)
-                                          enum: pair {"name":x},{x:"name"} */
+                                          enum: pair {"name":x},{x:"name"}
+                                          ptrs: lazily, ctypedescr of array */
     void *ct_extra;                    /* structs: first field (not a ref!)
                                           function types: cif_description
                                           primitives: prebuilt "cif" object */
@@ -1490,6 +1491,9 @@
             s = PyText_FromString(buffer);
         }
     }
+    else if ((cd->c_type->ct_flags & CT_ARRAY) && cd->c_type->ct_length < 0) {
+        s = PyText_FromFormat("sliced length %zd", get_array_length(cd));
+    }
     else {
         if (cd->c_data != NULL) {
             s = PyText_FromFormat("%p", cd->c_data);
@@ -1717,9 +1721,71 @@
 }
 
 static PyObject *
+new_array_type(CTypeDescrObject *ctptr, PyObject *lengthobj);   /* forward */
+
+static PyObject *
+cdata_slice(CDataObject *cd, PySliceObject *slice)
+{
+    Py_ssize_t start, stop;
+    CDataObject_own_length *scd;
+    CTypeDescrObject *ct = cd->c_type;
+
+    if (!(ct->ct_flags & (CT_ARRAY | CT_POINTER))) {
+        PyErr_Format(PyExc_TypeError, "cdata of type '%s' cannot be indexed",
+                     ct->ct_name);
+        return NULL;
+    }
+    start = PyInt_AsSsize_t(slice->start);
+    if (start == -1 && PyErr_Occurred()) {
+        if (slice->start == Py_None)
+            PyErr_SetString(PyExc_IndexError, "slice start must be specified");
+        return NULL;
+    }
+    stop = PyInt_AsSsize_t(slice->stop);
+    if (stop == -1 && PyErr_Occurred()) {
+        if (slice->stop == Py_None)
+            PyErr_SetString(PyExc_IndexError, "slice stop must be specified");
+        return NULL;
+    }
+    if (slice->step != Py_None) {
+        PyErr_SetString(PyExc_IndexError, "slice with step not supported");
+        return NULL;
+    }
+    if (start > stop) {
+        PyErr_SetString(PyExc_IndexError, "slice start > stop");
+        return NULL;
+    }
+
+    if (ct->ct_flags & CT_ARRAY)
+        ct = (CTypeDescrObject *)ct->ct_stuff;
+    assert(ct->ct_flags & CT_POINTER);
+    if (ct->ct_stuff == NULL) {
+        ct->ct_stuff = new_array_type(ct, Py_None);
+        if (ct->ct_stuff == NULL)
+            return NULL;
+    }
+    ct = (CTypeDescrObject *)ct->ct_stuff;
+
+    scd = (CDataObject_own_length *)PyObject_Malloc(
+              offsetof(CDataObject_own_length, alignment));
+    if (PyObject_Init((PyObject *)scd, &CData_Type) == NULL)
+        return NULL;
+    Py_INCREF(ct);
+    scd->head.c_type = ct;
+    scd->head.c_data = cd->c_data + ct->ct_itemdescr->ct_size * start;
+    scd->head.c_weakreflist = NULL;
+    scd->length = stop - start;
+    return (PyObject *)scd;
+}
+
+static PyObject *
 cdataowning_subscript(CDataObject *cd, PyObject *key)
 {
-    char *c = _cdata_get_indexed_ptr(cd, key);
+    char *c;
+    if (PySlice_Check(key))
+        return cdata_slice(cd, (PySliceObject *)key);
+
+    c = _cdata_get_indexed_ptr(cd, key);
     /* use 'mp_subscript' instead of 'sq_item' because we don't want
        negative indexes to be corrected automatically */
     if (c == NULL && PyErr_Occurred())
@@ -1738,7 +1804,11 @@
 static PyObject *
 cdata_subscript(CDataObject *cd, PyObject *key)
 {
-    char *c = _cdata_get_indexed_ptr(cd, key);
+    char *c;
+    if (PySlice_Check(key))
+        return cdata_slice(cd, (PySliceObject *)key);
+
+    c = _cdata_get_indexed_ptr(cd, key);
     /* use 'mp_subscript' instead of 'sq_item' because we don't want
        negative indexes to be corrected automatically */
     if (c == NULL && PyErr_Occurred())
@@ -3122,14 +3192,22 @@
 static PyObject *b_new_array_type(PyObject *self, PyObject *args)
 {
     PyObject *lengthobj;
-    CTypeDescrObject *td, *ctitem, *ctptr;
-    char extra_text[32];
-    Py_ssize_t length, arraysize;
+    CTypeDescrObject *ctptr;
 
     if (!PyArg_ParseTuple(args, "O!O:new_array_type",
                           &CTypeDescr_Type, &ctptr, &lengthobj))
         return NULL;
 
+    return new_array_type(ctptr, lengthobj);
+}
+
+static PyObject *
+new_array_type(CTypeDescrObject *ctptr, PyObject *lengthobj)
+{
+    CTypeDescrObject *td, *ctitem;
+    char extra_text[32];
+    Py_ssize_t length, arraysize;
+
     if (!(ctptr->ct_flags & CT_POINTER)) {
         PyErr_SetString(PyExc_TypeError, "first arg must be a pointer ctype");
         return NULL;
diff --git a/c/test_c.py b/c/test_c.py
--- a/c/test_c.py
+++ b/c/test_c.py
@@ -2574,3 +2574,19 @@
     for i in range(20):
         buf = buflist[i]
         assert buf[:] == str2bytes("hi there %d\x00" % i)
+
+def test_slice():
+    BIntP = new_pointer_type(new_primitive_type("int"))
+    BIntArray = new_array_type(BIntP, None)
+    c = newp(BIntArray, 5)
+    assert len(c) == 5
+    assert repr(c) == "<cdata 'int[]' owning 20 bytes>"
+    d = c[1:4]
+    assert len(d) == 3
+    assert repr(d) == "<cdata 'int[]' sliced length 3>"
+    d[0] = 123
+    d[2] = 456
+    assert c[1] == 123
+    assert c[3] == 456
+    py.test.raises(IndexError, "d[3]")
+    py.test.raises(IndexError, "d[-1]")
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to