Commits

Armin Rigo committed b68c5dd

getting a slice

Comments (0)

Files changed (2)

c/_cffi_backend.c

     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 */
             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);
 }
 
 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())
 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())
 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;
     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]")