[pypy-commit] pypy fix-bytearray-complexity: Add to RPython support for __getitem__, __setitem, __getslice__, __setslice__, and __len__
waedt
noreply at buildbot.pypy.org
Mon Jun 2 19:47:11 CEST 2014
Author: Tyler Wade <wayedt at gmail.com>
Branch: fix-bytearray-complexity
Changeset: r71878:5e3423ac75bf
Date: 2014-06-01 05:26 -0500
http://bitbucket.org/pypy/pypy/changeset/5e3423ac75bf/
Log: Add to RPython support for __getitem__, __setitem, __getslice__,
__setslice__, and __len__
diff --git a/rpython/annotator/binaryop.py b/rpython/annotator/binaryop.py
--- a/rpython/annotator/binaryop.py
+++ b/rpython/annotator/binaryop.py
@@ -719,6 +719,14 @@
return super(thistype, pair(ins1, ins2)).improve()
+class __extend__(pairtype(SomeInstance, SomeObject)):
+ def getitem((s_ins, s_idx)):
+ return s_ins._emulate_call("__getitem__", s_idx)
+
+ def setitem((s_ins, s_idx), s_value):
+ return s_ins._emulate_call("__setitem__", s_idx, s_value)
+
+
class __extend__(pairtype(SomeIterator, SomeIterator)):
def union((iter1, iter2)):
diff --git a/rpython/annotator/test/test_annrpython.py b/rpython/annotator/test/test_annrpython.py
--- a/rpython/annotator/test/test_annrpython.py
+++ b/rpython/annotator/test/test_annrpython.py
@@ -3937,6 +3937,78 @@
s = a.build_types(fn, [int])
assert isinstance(s, annmodel.SomeInteger)
+ def test_instance_getitem(self):
+ class A(object):
+ def __getitem__(self, i):
+ return i * i
+
+ def fn(i):
+ a = A()
+ return a[i]
+
+ a = self.RPythonAnnotator()
+ s = a.build_types(fn, [int])
+ assert len(a.translator.graphs) == 2 # fn, __getitem__
+ assert isinstance(s, annmodel.SomeInteger)
+
+ def test_instance_setitem(self):
+ class A(object):
+ def __setitem__(self, i, v):
+ self.value = i * v
+
+ def fn(i, v):
+ a = A()
+ a[i] = v
+ return a.value
+
+ a = self.RPythonAnnotator()
+ s = a.build_types(fn, [int, int])
+ assert len(a.translator.graphs) == 2 # fn, __setitem__
+ assert isinstance(s, annmodel.SomeInteger)
+
+ def test_instance_getslice(self):
+ class A(object):
+ def __getslice__(self, stop, start):
+ return "Test"[stop:start]
+
+ def fn():
+ a = A()
+ return a[0:2]
+
+ a = self.RPythonAnnotator()
+ s = a.build_types(fn, [])
+ assert len(a.translator.graphs) == 2 # fn, __getslice__
+ assert isinstance(s, annmodel.SomeString)
+
+ def test_instance_setslice(self):
+ class A(object):
+ def __setslice__(self, stop, start, value):
+ self.value = value
+
+ def fn():
+ a = A()
+ a[0:2] = '00'
+ return a.value
+
+ a = self.RPythonAnnotator()
+ s = a.build_types(fn, [])
+ assert len(a.translator.graphs) == 2 # fn, __setslice__
+ assert isinstance(s, annmodel.SomeString)
+
+ def test_instance_len(self):
+ class A(object):
+ def __len__(self):
+ return 0
+
+ def fn():
+ a = A()
+ return len(a)
+
+ a = self.RPythonAnnotator()
+ s = a.build_types(fn, [])
+ assert len(a.translator.graphs) == 2 # fn, __len__
+ assert isinstance(s, annmodel.SomeInteger)
+
def test_reversed(self):
def fn(n):
for elem in reversed([1, 2, 3, 4, 5]):
diff --git a/rpython/annotator/unaryop.py b/rpython/annotator/unaryop.py
--- a/rpython/annotator/unaryop.py
+++ b/rpython/annotator/unaryop.py
@@ -683,19 +683,27 @@
if not self.can_be_None:
s.const = True
+ def _emulate_call(self, meth_name, *args_s):
+ bk = getbookkeeper()
+ s_attr = self._true_getattr(meth_name)
+ # record for calltables
+ bk.emulate_pbc_call(bk.position_key, s_attr, args_s)
+ return s_attr.call(simple_args(args_s))
+
def iter(self):
- s_iterable = self._true_getattr('__iter__')
- bk = getbookkeeper()
- # record for calltables
- bk.emulate_pbc_call(bk.position_key, s_iterable, [])
- return s_iterable.call(simple_args([]))
+ return self._emulate_call('__iter__')
def next(self):
- s_next = self._true_getattr('next')
- bk = getbookkeeper()
- # record for calltables
- bk.emulate_pbc_call(bk.position_key, s_next, [])
- return s_next.call(simple_args([]))
+ return self._emulate_call('next')
+
+ def len(self):
+ return self._emulate_call('__len__')
+
+ def getslice(self, s_start, s_stop):
+ return self._emulate_call('__getslice__', s_start, s_stop)
+
+ def setslice(self, s_start, s_stop, s_iterable):
+ return self._emulate_call('__setslice__', s_start, s_stop, s_iterable)
class __extend__(SomeBuiltin):
def simple_call(self, *args):
diff --git a/rpython/rlib/buffer.py b/rpython/rlib/buffer.py
--- a/rpython/rlib/buffer.py
+++ b/rpython/rlib/buffer.py
@@ -12,6 +12,9 @@
def getlength(self):
raise NotImplementedError
+ def __len__(self):
+ return self.getlength()
+
def as_str(self):
"Returns an interp-level string with the whole content of the buffer."
# May be overridden.
@@ -21,14 +24,23 @@
"Returns the index'th character in the buffer."
raise NotImplementedError # Must be overriden. No bounds checks.
+ def __getitem__(self, i):
+ return self.getitem(i)
+
def getslice(self, start, stop, step, size):
# May be overridden. No bounds checks.
return ''.join([self.getitem(i) for i in range(start, stop, step)])
+ def __getslice__(self, start, stop):
+ return self.getslice(start, stop, 1, stop - start)
+
def setitem(self, index, char):
"Write a character into the buffer."
raise NotImplementedError # Must be overriden. No bounds checks.
+ def __setitem__(self, i, char):
+ return self.setitem(i, char)
+
def setslice(self, start, string):
# May be overridden. No bounds checks.
for i in range(len(string)):
diff --git a/rpython/rlib/test/test_buffer.py b/rpython/rlib/test/test_buffer.py
--- a/rpython/rlib/test/test_buffer.py
+++ b/rpython/rlib/test/test_buffer.py
@@ -4,7 +4,10 @@
def test_string_buffer():
buf = StringBuffer('hello world')
assert buf.getitem(4) == 'o'
+ assert buf.getitem(4) == buf[4]
assert buf.getlength() == 11
+ assert buf.getlength() == len(buf)
assert buf.getslice(1, 6, 1, 5) == 'ello '
+ assert buf.getslice(1, 6, 1, 5) == buf[1:6]
assert buf.getslice(1, 6, 2, 3) == 'el '
assert buf.as_str() == 'hello world'
diff --git a/rpython/rtyper/rclass.py b/rpython/rtyper/rclass.py
--- a/rpython/rtyper/rclass.py
+++ b/rpython/rtyper/rclass.py
@@ -7,6 +7,7 @@
from rpython.rtyper.lltypesystem.lltype import Void
from rpython.rtyper.rmodel import Repr, getgcflavor, inputconst
from rpython.rlib.objectmodel import UnboxedValue
+from rpython.tool.pairtype import pairtype
class FieldListAccessor(object):
@@ -390,7 +391,7 @@
raise NotImplementedError
def _emulate_call(self, hop, meth_name):
- vinst, = hop.inputargs(self)
+ vinst = hop.args_v[0]
clsdef = hop.args_s[0].classdef
s_unbound_attr = clsdef.find_attribute(meth_name).getvalue()
s_attr = clsdef.lookup_filter(s_unbound_attr, meth_name,
@@ -402,10 +403,10 @@
r_method = self.rtyper.getrepr(s_attr)
r_method.get_method_from_instance(self, vinst, hop.llops)
hop2 = hop.copy()
- hop2.spaceop = op.simple_call(hop.spaceop.args[0])
+ hop2.spaceop = op.simple_call(*hop.spaceop.args)
hop2.spaceop.result = hop.spaceop.result
- hop2.args_r = [r_method]
- hop2.args_s = [s_attr]
+ hop2.args_r[0] = r_method
+ hop2.args_s[0] = s_attr
return hop2.dispatch()
def rtype_iter(self, hop):
@@ -414,6 +415,15 @@
def rtype_next(self, hop):
return self._emulate_call(hop, 'next')
+ def rtype_getslice(self, hop):
+ return self._emulate_call(hop, "__getslice__")
+
+ def rtype_setslice(self, hop):
+ return self._emulate_call(hop, "__setslice__")
+
+ def rtype_len(self, hop):
+ return self._emulate_call(hop, "__len__")
+
def ll_str(self, i):
raise NotImplementedError
@@ -460,6 +470,16 @@
if len(seen) == oldlength:
break
+
+class __extend__(pairtype(AbstractInstanceRepr, Repr)):
+ def rtype_getitem((r_ins, r_obj), hop):
+ return r_ins._emulate_call(hop, "__getitem__")
+
+ def rtype_setitem((r_ins, r_obj), hop):
+ return r_ins._emulate_call(hop, "__setitem__")
+
+
+
# ____________________________________________________________
def rtype_new_instance(rtyper, classdef, llops, classcallhop=None):
diff --git a/rpython/rtyper/test/test_rclass.py b/rpython/rtyper/test/test_rclass.py
--- a/rpython/rtyper/test/test_rclass.py
+++ b/rpython/rtyper/test/test_rclass.py
@@ -1193,6 +1193,69 @@
assert self.interpret(f, [True]) == f(True)
assert self.interpret(f, [False]) == f(False)
+ def test_indexing(self):
+ class A(object):
+ def __init__(self, data):
+ self.data = data
+
+ def __getitem__(self, i):
+ return self.data[i]
+
+ def __setitem__(self, i, v):
+ self.data[i] = v
+
+ def __getslice__(self, start, stop):
+ assert start >= 0
+ assert stop >= 0
+ return self.data[start:stop]
+
+ def __setslice__(self, start, stop, v):
+ assert start >= 0
+ assert stop >= 0
+ i = 0
+ for n in range(start, stop):
+ self.data[n] = v[i]
+ i += 1
+
+ def getitem(i):
+ a = A("abcdefg")
+ return a[i]
+
+ def setitem(i, v):
+ a = A([0] * 5)
+ a[i] = v
+ return a[i]
+
+ def getslice(start, stop):
+ a = A([1, 2, 3, 4, 5, 6])
+ sum = 0
+ for i in a[start:stop]:
+ sum += i
+ return sum
+
+ def setslice(start, stop, i):
+ a = A([0] * stop)
+ a[start:stop] = range(start, stop)
+ return a[i]
+
+ assert self.interpret(getitem, [0]) == getitem(0)
+ assert self.interpret(getitem, [1]) == getitem(1)
+ assert self.interpret(setitem, [0, 5]) == setitem(0, 5)
+ assert self.interpret(getslice, [0, 4]) == getslice(0, 4)
+ assert self.interpret(getslice, [1, 4]) == getslice(1, 4)
+ assert self.interpret(setslice, [4, 6, 5]) == setslice(4, 6, 5)
+
+ def test_len(self):
+ class A(object):
+ def __len__(self):
+ return 5
+
+ def fn():
+ a = A()
+ return len(a)
+
+ assert self.interpret(fn, []) == fn()
+
def test_init_with_star_args(self):
class Base(object):
def __init__(self, a, b):
More information about the pypy-commit
mailing list