[pypy-commit] pypy nonmovable-list: The hardest bit is to give a consistent behavior before translation...
arigo
pypy.commits at gmail.com
Thu Jun 2 09:05:37 EDT 2016
Author: Armin Rigo <arigo at tunes.org>
Branch: nonmovable-list
Changeset: r84880:3013b870792c
Date: 2016-06-02 15:05 +0200
http://bitbucket.org/pypy/pypy/changeset/3013b870792c/
Log: The hardest bit is to give a consistent behavior before
translation...
diff --git a/rpython/rlib/rgc.py b/rpython/rlib/rgc.py
--- a/rpython/rlib/rgc.py
+++ b/rpython/rlib/rgc.py
@@ -1001,3 +1001,194 @@
def specialize_call(self, hop):
hop.exception_cannot_occur()
return hop.genop('gc_gettypeid', hop.args_v, resulttype=lltype.Signed)
+
+# ____________________________________________________________
+
+
+class _rawptr_missing_item(object):
+ pass
+_rawptr_missing_item = _rawptr_missing_item()
+
+
+class ListSupportingRawPtr(list):
+ """Calling this class is a no-op after translation. Before
+ translation, it returns a new instance of ListSupportingRawPtr,
+ on which rgc.nonmoving_raw_ptr_for_resizable_list() might be
+ used if needed. For now, only supports lists of chars.
+ """
+ __slots__ = ('_raw_items',) # either None or a rffi.CArray(Char)
+
+ def __init__(self, lst):
+ self._raw_items = None
+ self.__from_list(lst)
+
+ def __resize(self):
+ """Called before an operation changes the size of the list"""
+ if self._raw_items is not None:
+ list.__init__(self, self.__as_list())
+ self._raw_items = None
+
+ def __from_list(self, lst):
+ """Initialize the list from a copy of the list 'lst'."""
+ assert isinstance(lst, list)
+ for x in lst:
+ assert isinstance(x, str) and len(x) == 1
+ if self is lst:
+ return
+ if len(self) != len(lst):
+ self.__resize()
+ if self._raw_items is None:
+ list.__init__(self, lst)
+ else:
+ assert len(self) == self._raw_items._obj.getlength() == len(lst)
+ for i in range(len(self)):
+ self._raw_items[i] = lst[i]
+
+ def __as_list(self):
+ """Return a list (the same or a different one) which contains the
+ items in the regular way."""
+ if self._raw_items is None:
+ return self
+ length = self._raw_items._obj.getlength()
+ assert length == len(self)
+ return [self._raw_items[i] for i in range(length)]
+
+ def __getitem__(self, index):
+ if self._raw_items is None:
+ return list.__getitem__(self, index)
+ if index < 0:
+ index += len(self)
+ if not (0 <= index < len(self)):
+ raise IndexError
+ return self._raw_items[index]
+
+ def __setitem__(self, index, new):
+ if self._raw_items is None:
+ return list.__setitem__(self, index, new)
+ if index < 0:
+ index += len(self)
+ if not (0 <= index < len(self)):
+ raise IndexError
+ self._raw_items[index] = new
+
+ def __delitem__(self, index):
+ self.__resize()
+ list.__delitem__(self, index)
+
+ def __getslice__(self, i, j):
+ return list.__getslice__(self.__as_list(), i, j)
+
+ def __setslice__(self, i, j, new):
+ lst = self.__as_list()
+ list.__setslice__(lst, i, j, new)
+ self.__from_list(lst)
+
+ def __delslice__(self, i, j):
+ lst = self.__as_list()
+ list.__delslice__(lst, i, j)
+ self.__from_list(lst)
+
+ def __iter__(self):
+ try:
+ i = 0
+ while True:
+ yield self[i]
+ i += 1
+ except IndexError:
+ pass
+
+ def __reversed__(self):
+ i = len(self)
+ while i > 0:
+ i -= 1
+ yield self[i]
+
+ def __contains__(self, item):
+ return list.__contains__(self.__as_list(), item)
+
+ def __add__(self, other):
+ return list.__add__(self.__as_list(), other)
+
+ def __radd__(self, other):
+ other = list(other)
+ return list.__add__(other, self)
+
+ def __iadd__(self, other):
+ self.__resize()
+ return list.__iadd__(self, other)
+
+ def __eq__(self, other):
+ return list.__eq__(self.__as_list(), other)
+ def __ne__(self, other):
+ return list.__ne__(self.__as_list(), other)
+ def __ge__(self, other):
+ return list.__ge__(self.__as_list(), other)
+ def __gt__(self, other):
+ return list.__gt__(self.__as_list(), other)
+ def __le__(self, other):
+ return list.__le__(self.__as_list(), other)
+ def __lt__(self, other):
+ return list.__lt__(self.__as_list(), other)
+
+ def __mul__(self, other):
+ return list.__mul__(self.__as_list(), other)
+
+ def __rmul__(self, other):
+ return list.__mul__(self.__as_list(), other)
+
+ def __imul__(self, other):
+ self.__resize()
+ return list.__imul__(self, other)
+
+ def __repr__(self):
+ return 'ListSupportingRawPtr(%s)' % (list.__repr__(self.__as_list()),)
+
+ def append(self, object):
+ self.__resize()
+ return list.append(self, object)
+
+ def count(self, value):
+ return list.count(self.__as_list(), value)
+
+ def extend(self, iterable):
+ self.__resize()
+ return list.extend(self, iterable)
+
+ def index(self, value, *start_stop):
+ return list.index(self.__as_list(), value, *start_stop)
+
+ def insert(self, index, object):
+ self.__resize()
+ return list.insert(self, index, object)
+
+ def pop(self, *opt_index):
+ self.__resize()
+ return list.pop(self, *opt_index)
+
+ def remove(self, value):
+ self.__resize()
+ return list.remove(self, value)
+
+ def reverse(self):
+ lst = self.__as_list()
+ list.reverse(lst)
+ self.__from_list(lst)
+
+ def sort(self, *args, **kwds):
+ lst = self.__as_list()
+ list.sort(lst, *args, **kwds)
+ self.__from_list(lst)
+
+ def _nonmoving_raw_ptr_for_resizable_list(self):
+ if self._raw_items is None:
+ existing_items = list(self)
+ from rpython.rtyper.lltypesystem import lltype, rffi
+ self._raw_items = lltype.malloc(rffi.CArray(lltype.Char), len(self),
+ flavor='raw', immortal=True)
+ self.__from_list(existing_items)
+ assert self._raw_items is not None
+ return self._raw_items
+
+def nonmoving_raw_ptr_for_resizable_list(lst):
+ assert isinstance(lst, ListSupportingRawPtr)
+ return lst._nonmoving_raw_ptr_for_resizable_list()
diff --git a/rpython/rlib/test/test_rgc.py b/rpython/rlib/test/test_rgc.py
--- a/rpython/rlib/test/test_rgc.py
+++ b/rpython/rlib/test/test_rgc.py
@@ -1,6 +1,6 @@
from rpython.rtyper.test.test_llinterp import gengraph, interpret
from rpython.rtyper.error import TyperError
-from rpython.rtyper.lltypesystem import lltype, llmemory
+from rpython.rtyper.lltypesystem import lltype, llmemory, rffi
from rpython.rlib import rgc # Force registration of gc.collect
import gc
import py, sys
@@ -254,6 +254,36 @@
assert typer.custom_trace_funcs == [(TP, trace_func)]
+def test_nonmoving_raw_ptr_for_resizable_list():
+ def f(n):
+ lst = ['a', 'b', 'c']
+ lst = rgc.ListSupportingRawPtr(lst)
+ lst.append(chr(n))
+ assert lst[3] == chr(n)
+ assert lst[-1] == chr(n)
+ #
+ ptr = rgc.nonmoving_raw_ptr_for_resizable_list(lst)
+ assert lst[:] == ['a', 'b', 'c', chr(n)]
+ assert lltype.typeOf(ptr) == rffi.CArrayPtr(lltype.Char)
+ assert [ptr[i] for i in range(4)] == ['a', 'b', 'c', chr(n)]
+ #
+ lst[-3] = 'X'
+ assert ptr[1] == 'X'
+ ptr[2] = 'Y'
+ assert lst[-2] == 'Y'
+ #
+ addr = rffi.cast(lltype.Signed, ptr)
+ ptr = rffi.cast(rffi.CArrayPtr(lltype.Char), addr)
+ lst[-4] = 'g'
+ assert ptr[0] == 'g'
+ ptr[3] = 'H'
+ assert lst[-1] == 'H'
+ return lst
+ #
+ # direct untranslated run
+ lst = f(35)
+ assert isinstance(lst, rgc.ListSupportingRawPtr)
+
# ____________________________________________________________
@@ -368,7 +398,6 @@
assert fq._triggered == 1
def test_finalizer_trigger_calls_too_much(self):
- from rpython.rtyper.lltypesystem import lltype, rffi
external_func = rffi.llexternal("foo", [], lltype.Void)
# ^^^ with release_gil=True
class X(object):
More information about the pypy-commit
mailing list