Author: Armin Rigo <[email protected]>
Branch: py3.5-bytearray
Changeset: r88842:abe549159b0d
Date: 2016-12-03 11:29 +0100
http://bitbucket.org/pypy/pypy/changeset/abe549159b0d/

Log:    in-progress

diff --git a/pypy/objspace/std/bytearrayobject.py 
b/pypy/objspace/std/bytearrayobject.py
--- a/pypy/objspace/std/bytearrayobject.py
+++ b/pypy/objspace/std/bytearrayobject.py
@@ -10,6 +10,7 @@
 from rpython.rtyper.lltypesystem import rffi
 from rpython.rlib.rgc import (resizable_list_supporting_raw_ptr,
         nonmoving_raw_ptr_for_resizable_list)
+from rpython.rlib import jit
 
 from pypy.interpreter.baseobjspace import W_Root
 from pypy.interpreter.error import OperationError, oefmt
@@ -35,6 +36,7 @@
         self._data = resizable_list_supporting_raw_ptr(data)
         self._offset = 0
         # NOTE: the bytearray data is in 'self._data[self._offset:]'
+        _tweak_for_tests(self)
 
     def getdata(self):
         if self._offset > 0:
@@ -48,13 +50,13 @@
                            ''.join(self._data[self._offset:]))
 
     def buffer_w(self, space, flags):
-        return BytearrayBuffer(self._data, self._offset)
+        return BytearrayBuffer(self)
 
     def bytearray_list_of_chars_w(self, space):
         return self.getdata()
 
     def nonmovable_carray(self, space):
-        return BytearrayBuffer(self._data, self._offset).get_raw_address()
+        return BytearrayBuffer(self).get_raw_address()
 
     def _new(self, value):
         if value is self._data:
@@ -73,7 +75,7 @@
     def _len(self):
         return len(self._data) - self._offset
 
-    def _fixindex(self, space, index):
+    def _fixindex(self, space, index, errmsg="bytearray index out of range"):
         # for getitem/setitem/delitem of a single char
         if index >= 0:
             index += self._offset
@@ -82,7 +84,7 @@
             index += len(self._data)    # count from the end
             oob = index < self._offset
         if oob:
-            raise oefmt(space.w_IndexError, "bytearray index out of range")
+            raise OperationError(space.w_IndexError, space.wrap(errmsg))
         check_nonneg(index)
         return index
 
@@ -210,6 +212,7 @@
         data = [c for c in newbytesdata_w(space, w_source, encoding, errors)]
         self._data = resizable_list_supporting_raw_ptr(data)
         self._offset = 0
+        _tweak_for_tests(self)
 
     def descr_repr(self, space):
         s = self.getdata()
@@ -374,11 +377,20 @@
 
     def descr_setitem(self, space, w_index, w_other):
         if isinstance(w_index, W_SliceObject):
-            XXX
-            oldsize = len(self.data)
+            sequence2 = [c for c in makebytesdata_w(space, w_other)]
+            oldsize = self._len()
             start, stop, step, slicelength = w_index.indices4(space, oldsize)
-            sequence2 = [c for c in makebytesdata_w(space, w_other)]
-            _setitem_slice_helper(space, self.data, start, step,
+            if start == 0 and step == 1 and len(sequence2) <= slicelength:
+                self._delete_from_start(slicelength - len(sequence2))
+                slicelength = len(sequence2)
+                if slicelength == 0:
+                    return
+                data = self._data
+                start += self._offset
+                #stop += self._offset---not used
+            else:
+                data = self.getdata()
+            _setitem_slice_helper(space, data, start, step,
                                   slicelength, sequence2, empty_elem='\x00')
         else:
             idx = space.getindex_w(w_index, space.w_IndexError, "bytearray")
@@ -387,14 +399,27 @@
 
     def descr_delitem(self, space, w_idx):
         if isinstance(w_idx, W_SliceObject):
-            XXX
-            start, stop, step, slicelength = w_idx.indices4(space,
-                                                            len(self.data))
-            _delitem_slice_helper(space, self.data, start, step, slicelength)
+            start, stop, step, slicelength = w_idx.indices4(space, self._len())
+            if start == 0 and step == 1:
+                self._delete_from_start(slicelength)
+            else:
+                _delitem_slice_helper(space, self.getdata(),
+                                      start, step, slicelength)
         else:
-            XXX # case of del b[0]
             idx = space.getindex_w(w_idx, space.w_IndexError, "bytearray")
-            del self._data[self._fixindex(space, idx)]
+            idx = self._fixindex(space, idx)
+            if idx == self._offset:    # fast path for del x[0] or del[-len]
+                self._delete_from_start(1)
+            else:
+                del self._data[idx]
+
+    def _delete_from_start(self, n):
+        self._offset += n
+        jit.conditional_call(self._offset > len(self._data) / 2 + 15,
+                             self._shrink_after_delete_from_start)
+
+    def _shrink_after_delete_from_start(self):
+        self.getdata()
 
     def descr_append(self, space, w_item):
         self._data.append(getbytevalue(space, w_item))
@@ -407,32 +432,33 @@
 
     def descr_insert(self, space, w_idx, w_other):
         where = space.int_w(w_idx)
-        length = len(self.data)
+        val = getbytevalue(space, w_other)
+        data = self.getdata()
+        length = len(data)
         index = get_positive_index(where, length)
-        val = getbytevalue(space, w_other)
-        self.data.insert(index, val)
+        data.insert(index, val)
 
     @unwrap_spec(w_idx=WrappedDefault(-1))
     def descr_pop(self, space, w_idx):
         index = space.int_w(w_idx)
-        try:
-            result = self.data.pop(index)
-        except IndexError:
-            if not self.data:
-                raise oefmt(space.w_IndexError, "pop from empty bytearray")
-            raise oefmt(space.w_IndexError, "pop index out of range")
+        if self._len() == 0:
+            raise oefmt(space.w_IndexError, "pop from empty bytearray")
+        index = self._fixindex(space, index, "pop index out of range")
+        result = self._data.pop(index)
         return space.wrap(ord(result))
 
     def descr_remove(self, space, w_char):
         char = space.int_w(space.index(w_char))
-        try:
-            self.data.remove(chr(char))
-        except ValueError:
-            raise oefmt(space.w_ValueError, "value not found in bytearray")
+        _data = self._data
+        for index in range(self._offset, len(_data)):
+            if ord(_data[index]) == char:
+                del _data[index]
+                return
+        raise oefmt(space.w_ValueError, "value not found in bytearray")
 
     def descr_add(self, space, w_other):
         if isinstance(w_other, W_BytearrayObject):
-            return self._new(self.data + w_other.data)
+            return self._new(self.getdata() + w_other.getdata())
 
         if isinstance(w_other, W_BytesObject):
             return self._add(self._op_val(space, w_other))
@@ -447,19 +473,21 @@
 
     @specialize.argtype(1)
     def _add(self, other):
-        return self._new(self.data + [other[i] for i in range(len(other))])
+        return self._new(self.getdata() + [other[i] for i in 
range(len(other))])
 
     def descr_reverse(self, space):
-        self.data.reverse()
+        self.getdata().reverse()
 
     def descr_clear(self, space):
-        self.data = []
+        self._data = []
+        self._offset = 0
 
     def descr_copy(self, space):
-        return self._new(self.data[:])
+        return self._new(self._data[self._offset:])
 
     def descr_hex(self, space):
-        return _array_to_hexstring(space, self.data, len(self.data), True)
+        data = self.getdata()
+        return _array_to_hexstring(space, data, len(data), True)
 
     def descr_mod(self, space, w_values):
         return mod_format(space, self, w_values, fmt_type=FORMAT_BYTEARRAY)
@@ -1235,37 +1263,48 @@
 
 class BytearrayBuffer(Buffer):
     _immutable_ = True
+    readonly = False
 
-    def __init__(self, data, offset):
-        self._data = data
-        self._offset = offset
+    def __init__(self, ba):
+        self.ba = ba     # the W_BytearrayObject
 
     def getlength(self):
-        return len(self.data)
+        return self.ba._len()
 
     def getitem(self, index):
-        return self.data[index]
+        ba = self.ba
+        return ba._data[ba._offset + index]
 
     def setitem(self, index, char):
-        self.data[index] = char
+        ba = self.ba
+        ba._data[ba._offset + index] = char
 
     def getslice(self, start, stop, step, size):
         if size == 0:
             return ""
         if step == 1:
             assert 0 <= start <= stop
-            if start == 0 and stop == len(self.data):
-                return "".join(self.data)
-            return "".join(self.data[start:stop])
+            ba = self.ba
+            start += ba._offset
+            stop += ba._offset
+            data = ba._data
+            if start != 0 or stop != len(data):
+                data = data[start:stop]
+            return "".join(data)
         return Buffer.getslice(self, start, stop, step, size)
 
     def setslice(self, start, string):
         # No bounds checks.
+        ba = self.ba
+        start += ba._offset
         for i in range(len(string)):
-            self.data[start + i] = string[i]
+            ba._data[start + i] = string[i]
 
     def get_raw_address(self):
-        return nonmoving_raw_ptr_for_resizable_list(self.data)
+        ba = self.ba
+        p = nonmoving_raw_ptr_for_resizable_list(ba._data)
+        p = rffi.ptradd(p, ba._offset)
+        return p
 
 
 @specialize.argtype(1)
@@ -1276,3 +1315,6 @@
         if selfvalue[i] > buffer[i]:
             return 1
     return 0
+
+def _tweak_for_tests(w_bytearray):
+    "Patched in test_bytearray.py"
diff --git a/pypy/objspace/std/test/test_bytearrayobject.py 
b/pypy/objspace/std/test/test_bytearrayobject.py
--- a/pypy/objspace/std/test/test_bytearrayobject.py
+++ b/pypy/objspace/std/test/test_bytearrayobject.py
@@ -1,10 +1,27 @@
 # coding: utf-8
 
+import random
 from pypy import conftest
+from pypy.objspace.std import bytearrayobject
+
+class DontAccess(object):
+    pass
+dont_access = DontAccess()
+
 
 class AppTestBytesArray:
     def setup_class(cls):
         cls.w_runappdirect = cls.space.wrap(conftest.option.runappdirect)
+        def tweak(w_bytearray):
+            n = random.randint(-3, 16)
+            if n > 0:
+                w_bytearray._data = [dont_access] * n + w_bytearray._data
+                w_bytearray._offset += n
+        cls._old_tweak = [bytearrayobject._tweak_for_tests]
+        bytearrayobject._tweak_for_tests = tweak
+
+    def teardown_class(cls):
+        [bytearrayobject._tweak_for_tests] = cls._old_tweak
 
     def test_basics(self):
         b = bytearray()
@@ -345,6 +362,20 @@
         b.reverse()
         assert b == bytearray(b'olleh')
 
+    def test_delitem_from_front(self):
+        b = bytearray(b'abcdefghij')
+        del b[0]
+        del b[0]
+        assert len(b) == 8
+        assert b == bytearray(b'cdefghij')
+        del b[-8]
+        del b[-7]
+        assert len(b) == 6
+        assert b == bytearray(b'efghij')
+        del b[:3]
+        assert len(b) == 3
+        assert b == bytearray(b'hij')
+
     def test_delitem(self):
         b = bytearray(b'abc')
         del b[1]
@@ -427,6 +458,18 @@
         raises(TypeError, b.extend, [object()])
         raises(TypeError, b.extend, "unicode")
 
+    def test_setitem_from_front(self):
+        b = bytearray(b'abcdefghij')
+        b[:2] = b''
+        assert len(b) == 8
+        assert b == bytearray(b'cdefghij')
+        b[:3] = b'X'
+        assert len(b) == 6
+        assert b == bytearray(b'Xfghij')
+        b[:2] = b'ABC'
+        assert len(b) == 7
+        assert b == bytearray(b'ABCghij')
+
     def test_setslice(self):
         b = bytearray(b'hello')
         b[:] = [ord(c) for c in 'world']
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to