Author: Matti Picus <[email protected]>
Branch: 
Changeset: r86125:72d14a4de609
Date: 2016-08-10 07:01 +0300
http://bitbucket.org/pypy/pypy/changeset/72d14a4de609/

Log:    test, fix PySequence_Fast getslice; remove outdated document

diff --git a/pypy/module/cpyext/c-api.txt b/pypy/module/cpyext/c-api.txt
deleted file mode 100644
--- a/pypy/module/cpyext/c-api.txt
+++ /dev/null
@@ -1,71 +0,0 @@
-Reference Count
-===============
-
-XXX
-
-Borrowed References
-===================
-
-XXX
-
-PyStringObject support
-======================
-
-The problem
------------
-
-PyString_AsString() returns a (non-movable) pointer to the underlying
-buffer, whereas pypy strings are movable.  C code may temporarily
-store this address and use it, as long as it owns a reference to the
-PyObject.  There is no "release" function to specify that the pointer
-is not needed any more.
-
-Note that the pointer may be used to fill the initial value of
-string. This is valid only when the string was just allocated, and is
-not used elsewhere.
-
-Proposed solution
------------------
-
-Our emulation of the PyStringObject contains an additional member: a
-pointer to a char buffer; it may be NULL.
-
-- A string allocated by pypy will be converted into a PyStringObject
-  with a NULL buffer.  When PyString_AsString() is called, memory is
-  allocated (with flavor='raw') and content is copied.
-
-- A string allocated with PyString_FromStringAndSize(NULL, size) will
-  allocate a buffer with the specified size, but the reference won't
-  be stored in the global map py_objects_r2w; there won't be a
-  corresponding object in pypy.  When from_ref() or Py_INCREF() is
-  called, the pypy string is created, and added in py_objects_r2w.
-  The buffer is then supposed to be immutable.
-
-- _PyString_Resize works only on not-yet-pypy'd strings, and returns a
-  similar object.
-
-- PyString_Size don't need to force the object. (in this case, another
-  "size" member is needed)
-
-- There could be an (expensive!) check in from_ref() that the buffer
-  still corresponds to the pypy gc-managed string.
-
-PySequence_Fast support
-======================
-There are five functions for fast sequence access offered by the CPython API:
-
-PyObject* PySequence_Fast(PyObject *o, const char *m)
-
-PyObject* PySequence_Fast_GET_ITEM(    PyObject *o, int i)
-
-PyObject** PySequence_Fast_ITEMS(      PyObject *o)
-
-PyObject* PySequence_ITEM(     PyObject *o, int i)
-
-int PySequence_Fast_GET_SIZE(  PyObject *o)
-
-PyPy supports four of these, but does not support PySequence_Fast_ITEMS.
-(Various ways to support PySequence_Fast_ITEMS were considered. They all had
-two things in common: they would have taken a lot of work, and they would have
-resulted in incomplete semantics or in poor performance. We decided that a slow
-implementation of PySequence_Fast_ITEMS was not very useful.)
diff --git a/pypy/module/cpyext/sequence.py b/pypy/module/cpyext/sequence.py
--- a/pypy/module/cpyext/sequence.py
+++ b/pypy/module/cpyext/sequence.py
@@ -10,7 +10,7 @@
 from pypy.objspace.std import tupleobject
 
 from pypy.module.cpyext.tupleobject import PyTuple_Check, PyTuple_SetItem
-from pypy.module.cpyext.object import Py_IncRef, Py_DecRef
+from pypy.module.cpyext.pyobject import decref
 
 from pypy.module.cpyext.dictobject import PyDict_Check
 
@@ -252,7 +252,7 @@
     def setitem(self, w_list, index, w_obj):
         storage = self.unerase(w_list.lstorage)
         index = self._check_index(index, storage._length)
-        Py_DecRef(w_list.space, storage._elems[index])
+        decref(w_list.space, storage._elems[index])
         storage._elems[index] = make_ref(w_list.space, w_obj)
 
     def length(self, w_list):
@@ -264,9 +264,8 @@
         return storage._elems
 
     def getslice(self, w_list, start, stop, step, length):
-        #storage = self.unerase(w_list.lstorage)
-        raise oefmt(w_list.space.w_NotImplementedError,
-                    "settting a slice of a PySequence_Fast is not supported")
+        w_list.switch_to_object_strategy()
+        return w_list.strategy.getslice(w_list, start, stop, step, length)
 
     def getitems(self, w_list):
         # called when switching list strategy, so convert storage
@@ -389,5 +388,5 @@
 
     def __del__(self):
         for i in range(self._length):
-            Py_DecRef(self.space, self._elems[i])
+            decref(self.space, self._elems[i])
         lltype.free(self._elems, flavor='raw')
diff --git a/pypy/module/cpyext/test/test_sequence.py 
b/pypy/module/cpyext/test/test_sequence.py
--- a/pypy/module/cpyext/test/test_sequence.py
+++ b/pypy/module/cpyext/test/test_sequence.py
@@ -78,6 +78,17 @@
         assert api.PySequence_SetSlice(w_t, 1, 1, space.wrap((3,))) == 0
         assert space.eq_w(w_t, space.wrap([1, 3, 5]))
 
+    def test_get_slice_fast(self, space, api):
+        w_t = space.wrap([1, 2, 3, 4, 5])
+        api.PySequence_Fast(w_t, "foo") # converts
+        assert space.unwrap(api.PySequence_GetSlice(w_t, 2, 4)) == [3, 4]
+        assert space.unwrap(api.PySequence_GetSlice(w_t, 1, -1)) == [2, 3, 4]
+
+        assert api.PySequence_DelSlice(w_t, 1, 4) == 0
+        assert space.eq_w(w_t, space.wrap([1, 5]))
+        assert api.PySequence_SetSlice(w_t, 1, 1, space.wrap((3,))) == 0
+        assert space.eq_w(w_t, space.wrap([1, 3, 5]))
+
     def test_iter(self, space, api):
         w_t = space.wrap((1, 2))
         w_iter = api.PySeqIter_New(w_t)
@@ -226,18 +237,33 @@
         assert space.int_w(space.len(w_l)) == 10
 
 
-class XAppTestSequenceObject(AppTestCpythonExtensionBase):
-    def test_sequenceobject(self):
+class AppTestSequenceObject(AppTestCpythonExtensionBase):
+    def test_fast(self):
         module = self.import_extension('foo', [
             ("test_fast_sequence", "METH_VARARGS",
              """
-                PyObject * o = PyTuple_GetItem(args, 0);
+                int size, i;
+                PyTypeObject * common_type;
+                PyObject *foo, **objects;
+                PyObject * seq = PyTuple_GetItem(args, 0);
                 /* XXX assert it is a tuple */
-                PyObject *foo = PySequence_Fast(o, "some string");
-                PyObject ** res = PySequence_Fast_ITEMS(foo);
-                /* XXX do some kind of test on res */
-                /* XXX now what? who manages res's refcount? */
+                if (seq == NULL)
+                    Py_RETURN_NONE;
+                foo = PySequence_Fast(seq, "some string");
+                objects = PySequence_Fast_ITEMS(foo);
+                size = PySequence_Fast_GET_SIZE(seq);
+                common_type = size > 0 ? Py_TYPE(objects[0]) : NULL;
+                for (i = 1; i < size; ++i) {
+                    if (Py_TYPE(objects[i]) != common_type) {
+                        common_type = NULL;
+                        break;
+                    }
+                }
+                Py_DECREF(foo);
+                Py_DECREF(common_type);
                 return PyBool_FromLong(1);
              """)])
-        assert module.test_fast_sequence([1, 2, 3, 4])
+        s = [1, 2, 3, 4]
+        assert module.test_fast_sequence(s[0:-1])
+        assert module.test_fast_sequence(s[::-1])
 
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to