[pypy-commit] pypy disable_merge_different_int_types: merge default
bivab
noreply at buildbot.pypy.org
Mon Nov 28 15:55:55 CET 2011
Author: David Schneider <david.schneider at picle.org>
Branch: disable_merge_different_int_types
Changeset: r49913:033150c474a1
Date: 2011-11-28 15:54 +0100
http://bitbucket.org/pypy/pypy/changeset/033150c474a1/
Log: merge default
diff too long, truncating to 10000 out of 10581 lines
diff --git a/py/_code/code.py b/py/_code/code.py
--- a/py/_code/code.py
+++ b/py/_code/code.py
@@ -307,7 +307,7 @@
self._striptext = 'AssertionError: '
self._excinfo = tup
self.type, self.value, tb = self._excinfo
- self.typename = self.type.__name__
+ self.typename = getattr(self.type, "__name__", "???")
self.traceback = py.code.Traceback(tb)
def __repr__(self):
diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py
--- a/pypy/config/pypyoption.py
+++ b/pypy/config/pypyoption.py
@@ -281,6 +281,9 @@
"actually create the full list until the resulting "
"list is mutated",
default=False),
+ BoolOption("withliststrategies",
+ "enable optimized ways to store lists of primitives ",
+ default=True),
BoolOption("withtypeversion",
"version type objects when changing them",
diff --git a/pypy/config/translationoption.py b/pypy/config/translationoption.py
--- a/pypy/config/translationoption.py
+++ b/pypy/config/translationoption.py
@@ -69,8 +69,8 @@
"statistics": [("translation.gctransformer", "framework")],
"generation": [("translation.gctransformer", "framework")],
"hybrid": [("translation.gctransformer", "framework")],
- "boehm": [("translation.gctransformer", "boehm"),
- ("translation.continuation", False)], # breaks
+ "boehm": [("translation.continuation", False), # breaks
+ ("translation.gctransformer", "boehm")],
"markcompact": [("translation.gctransformer", "framework")],
"minimark": [("translation.gctransformer", "framework")],
},
diff --git a/pypy/doc/config/objspace.std.withliststrategies.txt b/pypy/doc/config/objspace.std.withliststrategies.txt
new file mode 100644
--- /dev/null
+++ b/pypy/doc/config/objspace.std.withliststrategies.txt
@@ -0,0 +1,2 @@
+Enable list strategies: Use specialized representations for lists of primitive
+objects, such as ints.
diff --git a/pypy/doc/cpython_differences.rst b/pypy/doc/cpython_differences.rst
--- a/pypy/doc/cpython_differences.rst
+++ b/pypy/doc/cpython_differences.rst
@@ -262,6 +262,26 @@
documented as such (as e.g. for hasattr()), in most cases PyPy
lets the exception propagate instead.
+Object Identity of Primitive Values, ``is`` and ``id``
+-------------------------------------------------------
+
+Object identity of primitive values works by value equality, not by identity of
+the wrapper. This means that ``x + 1 is x + 1`` is always true, for arbitrary
+integers ``x``. The rule applies for the following types:
+
+ - ``int``
+
+ - ``float``
+
+ - ``long``
+
+ - ``complex``
+
+This change requires some changes to ``id`` as well. ``id`` fulfills the
+following condition: ``x is y <=> id(x) == id(y)``. Therefore ``id`` of the
+above types will return a value that is computed from the argument, and can
+thus be larger than ``sys.maxint`` (i.e. it can be an arbitrary long).
+
Miscellaneous
-------------
@@ -284,14 +304,5 @@
never a dictionary as it sometimes is in CPython. Assigning to
``__builtins__`` has no effect.
-* Do not compare immutable objects with ``is``. For example on CPython
- it is true that ``x is 0`` works, i.e. does the same as ``type(x) is
- int and x == 0``, but it is so by accident. If you do instead
- ``x is 1000``, then it stops working, because 1000 is too large and
- doesn't come from the internal cache. In PyPy it fails to work in
- both cases, because we have no need for a cache at all.
-
-* Also, object identity of immutable keys in dictionaries is not necessarily
- preserved.
.. include:: _ref.txt
diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -188,6 +188,12 @@
# -------------------------------------------------------------------
+ def is_w(self, space, w_other):
+ return self is w_other
+
+ def unique_id(self, space):
+ return space.wrap(compute_unique_id(self))
+
def str_w(self, space):
w_msg = typed_unwrap_error_msg(space, "string", self)
raise OperationError(space.w_TypeError, w_msg)
@@ -681,9 +687,17 @@
"""shortcut for space.is_true(space.eq(w_obj1, w_obj2))"""
return self.is_w(w_obj1, w_obj2) or self.is_true(self.eq(w_obj1, w_obj2))
- def is_w(self, w_obj1, w_obj2):
- """shortcut for space.is_true(space.is_(w_obj1, w_obj2))"""
- return self.is_true(self.is_(w_obj1, w_obj2))
+ def is_(self, w_one, w_two):
+ return self.newbool(self.is_w(w_one, w_two))
+
+ def is_w(self, w_one, w_two):
+ # done by a method call on w_two (and not on w_one, because of the
+ # expected programming style where we say "if x is None" or
+ # "if x is object").
+ return w_two.is_w(self, w_one)
+
+ def id(self, w_obj):
+ return w_obj.unique_id(self)
def hash_w(self, w_obj):
"""shortcut for space.int_w(space.hash(w_obj))"""
@@ -879,6 +893,16 @@
"""
return self.unpackiterable(w_iterable, expected_length)
+ def listview_str(self, w_list):
+ """ Return a list of unwrapped strings out of a list of strings. If the
+ argument is not a list or does not contain only strings, return None.
+ May return None anyway.
+ """
+ return None
+
+ def newlist_str(self, list_s):
+ return self.newlist([self.wrap(s) for s in list_s])
+
@jit.unroll_safe
def exception_match(self, w_exc_type, w_check_class):
"""Checks if the given exception type matches 'w_check_class'."""
@@ -1013,9 +1037,6 @@
def isinstance_w(self, w_obj, w_type):
return self.is_true(self.isinstance(w_obj, w_type))
- def id(self, w_obj):
- return self.wrap(compute_unique_id(w_obj))
-
# The code below only works
# for the simple case (new-style instance).
# These methods are patched with the full logic by the __builtin__
diff --git a/pypy/interpreter/generator.py b/pypy/interpreter/generator.py
--- a/pypy/interpreter/generator.py
+++ b/pypy/interpreter/generator.py
@@ -1,8 +1,9 @@
+from pypy.interpreter.baseobjspace import Wrappable
from pypy.interpreter.error import OperationError
-from pypy.interpreter.baseobjspace import Wrappable
from pypy.interpreter.gateway import NoneNotWrapped
+from pypy.interpreter.pyopcode import LoopBlock
from pypy.rlib import jit
-from pypy.interpreter.pyopcode import LoopBlock
+from pypy.rlib.objectmodel import specialize
class GeneratorIterator(Wrappable):
@@ -156,38 +157,43 @@
break
block = block.previous
- def unpack_into(self, results_w):
- """This is a hack for performance: runs the generator and collects
- all produced items in a list."""
- # XXX copied and simplified version of send_ex()
- space = self.space
- if self.running:
- raise OperationError(space.w_ValueError,
- space.wrap('generator already executing'))
- frame = self.frame
- if frame is None: # already finished
- return
- self.running = True
- try:
- pycode = self.pycode
- while True:
- jitdriver.jit_merge_point(self=self, frame=frame,
- results_w=results_w,
- pycode=pycode)
- try:
- w_result = frame.execute_frame(space.w_None)
- except OperationError, e:
- if not e.match(space, space.w_StopIteration):
- raise
- break
- # if the frame is now marked as finished, it was RETURNed from
- if frame.frame_finished_execution:
- break
- results_w.append(w_result) # YIELDed
- finally:
- frame.f_backref = jit.vref_None
- self.running = False
- self.frame = None
-
-jitdriver = jit.JitDriver(greens=['pycode'],
- reds=['self', 'frame', 'results_w'])
+ # Results can be either an RPython list of W_Root, or it can be an
+ # app-level W_ListObject, which also has an append() method, that's why we
+ # generate 2 versions of the function and 2 jit drivers.
+ def _create_unpack_into():
+ jitdriver = jit.JitDriver(greens=['pycode'],
+ reds=['self', 'frame', 'results'])
+ def unpack_into(self, results):
+ """This is a hack for performance: runs the generator and collects
+ all produced items in a list."""
+ # XXX copied and simplified version of send_ex()
+ space = self.space
+ if self.running:
+ raise OperationError(space.w_ValueError,
+ space.wrap('generator already executing'))
+ frame = self.frame
+ if frame is None: # already finished
+ return
+ self.running = True
+ try:
+ pycode = self.pycode
+ while True:
+ jitdriver.jit_merge_point(self=self, frame=frame,
+ results=results, pycode=pycode)
+ try:
+ w_result = frame.execute_frame(space.w_None)
+ except OperationError, e:
+ if not e.match(space, space.w_StopIteration):
+ raise
+ break
+ # if the frame is now marked as finished, it was RETURNed from
+ if frame.frame_finished_execution:
+ break
+ results.append(w_result) # YIELDed
+ finally:
+ frame.f_backref = jit.vref_None
+ self.running = False
+ self.frame = None
+ return unpack_into
+ unpack_into = _create_unpack_into()
+ unpack_into_w = _create_unpack_into()
\ No newline at end of file
diff --git a/pypy/interpreter/test/test_function.py b/pypy/interpreter/test/test_function.py
--- a/pypy/interpreter/test/test_function.py
+++ b/pypy/interpreter/test/test_function.py
@@ -587,7 +587,7 @@
assert isinstance(meth2, Method)
assert meth2.call_args(args) == obj1
# Check method returned from unbound_method.__get__()
- w_meth3 = descr_function_get(space, func, None, space.type(obj2))
+ w_meth3 = descr_function_get(space, func, space.w_None, space.type(obj2))
meth3 = space.unwrap(w_meth3)
w_meth4 = meth3.descr_method_get(obj2, space.w_None)
meth4 = space.unwrap(w_meth4)
diff --git a/pypy/interpreter/test/test_objspace.py b/pypy/interpreter/test/test_objspace.py
--- a/pypy/interpreter/test/test_objspace.py
+++ b/pypy/interpreter/test/test_objspace.py
@@ -63,10 +63,13 @@
def test_unpackiterable(self):
space = self.space
w = space.wrap
- l = [w(1), w(2), w(3), w(4)]
+ l = [space.newlist([]) for l in range(4)]
w_l = space.newlist(l)
- assert space.unpackiterable(w_l) == l
- assert space.unpackiterable(w_l, 4) == l
+ l1 = space.unpackiterable(w_l)
+ l2 = space.unpackiterable(w_l, 4)
+ for i in range(4):
+ assert space.is_w(l1[i], l[i])
+ assert space.is_w(l2[i], l[i])
err = raises(OperationError, space.unpackiterable, w_l, 3)
assert err.value.match(space, space.w_ValueError)
err = raises(OperationError, space.unpackiterable, w_l, 5)
diff --git a/pypy/jit/metainterp/history.py b/pypy/jit/metainterp/history.py
--- a/pypy/jit/metainterp/history.py
+++ b/pypy/jit/metainterp/history.py
@@ -999,12 +999,9 @@
"found %d %r, expected %d" % (found, insn, expected_count))
return insns
- def check_loops(self, expected=None, everywhere=False, **check):
+ def check_resops(self, expected=None, **check):
insns = {}
for loop in self.loops:
- if not everywhere:
- if getattr(loop, '_ignore_during_counting', False):
- continue
insns = loop.summary(adding_insns=insns)
if expected is not None:
insns.pop('debug_merge_point', None)
@@ -1015,7 +1012,7 @@
assert found == expected_count, (
"found %d %r, expected %d" % (found, insn, expected_count))
return insns
-
+
def check_consistency(self):
"NOT_RPYTHON"
for loop in self.loops:
diff --git a/pypy/jit/metainterp/optimizeopt/optimizer.py b/pypy/jit/metainterp/optimizeopt/optimizer.py
--- a/pypy/jit/metainterp/optimizeopt/optimizer.py
+++ b/pypy/jit/metainterp/optimizeopt/optimizer.py
@@ -564,9 +564,12 @@
descr = op.getdescr()
assert isinstance(descr, compile.ResumeGuardDescr)
modifier = resume.ResumeDataVirtualAdder(descr, self.resumedata_memo)
- newboxes = modifier.finish(self.values, self.pendingfields)
- if len(newboxes) > self.metainterp_sd.options.failargs_limit: # XXX be careful here
- compile.giveup()
+ try:
+ newboxes = modifier.finish(self.values, self.pendingfields)
+ if len(newboxes) > self.metainterp_sd.options.failargs_limit:
+ raise resume.TagOverflow
+ except resume.TagOverflow:
+ raise compile.giveup()
descr.store_final_boxes(op, newboxes)
#
if op.getopnum() == rop.GUARD_VALUE:
diff --git a/pypy/jit/metainterp/resume.py b/pypy/jit/metainterp/resume.py
--- a/pypy/jit/metainterp/resume.py
+++ b/pypy/jit/metainterp/resume.py
@@ -93,12 +93,14 @@
TAGMASK = 3
+class TagOverflow(Exception):
+ pass
+
def tag(value, tagbits):
- if tagbits >> 2:
- raise ValueError
+ assert 0 <= tagbits <= 3
sx = value >> 13
if sx != 0 and sx != -1:
- raise ValueError
+ raise TagOverflow
return rffi.r_short(value<<2|tagbits)
def untag(value):
@@ -153,7 +155,7 @@
return self._newconst(const)
try:
return tag(val, TAGINT)
- except ValueError:
+ except TagOverflow:
pass
tagged = self.large_ints.get(val, UNASSIGNED)
if not tagged_eq(tagged, UNASSIGNED):
@@ -429,8 +431,7 @@
fieldnum = self._gettagged(fieldbox)
# the index is limited to 2147483647 (64-bit machines only)
if itemindex > 2147483647:
- from pypy.jit.metainterp import compile
- compile.giveup()
+ raise TagOverflow
itemindex = rffi.cast(rffi.INT, itemindex)
#
rd_pendingfields[i].lldescr = lldescr
diff --git a/pypy/jit/metainterp/test/support.py b/pypy/jit/metainterp/test/support.py
--- a/pypy/jit/metainterp/test/support.py
+++ b/pypy/jit/metainterp/test/support.py
@@ -155,9 +155,9 @@
class JitMixin:
basic = True
- def check_loops(self, expected=None, everywhere=False, **check):
- get_stats().check_loops(expected=expected, everywhere=everywhere,
- **check)
+ def check_resops(self, expected=None, **check):
+ get_stats().check_resops(expected=expected, **check)
+
def check_loop_count(self, count):
"""NB. This is a hack; use check_tree_loop_count() or
check_enter_count() for the real thing.
diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py
--- a/pypy/jit/metainterp/test/test_ajit.py
+++ b/pypy/jit/metainterp/test/test_ajit.py
@@ -79,9 +79,8 @@
res = self.meta_interp(f, [6, 7])
assert res == 42
self.check_loop_count(1)
- self.check_loops({'guard_true': 1,
- 'int_add': 1, 'int_sub': 1, 'int_gt': 1,
- 'jump': 1})
+ self.check_resops({'jump': 2, 'int_gt': 2, 'int_add': 2, 'guard_true': 2, 'int_sub': 2})
+
if self.basic:
found = 0
for op in get_stats().loops[0]._all_operations():
@@ -108,7 +107,7 @@
res = self.meta_interp(f, [6, 7])
assert res == 1323
self.check_loop_count(1)
- self.check_loops(int_mul=1)
+ self.check_resops(int_mul=3)
def test_loop_variant_mul_ovf(self):
myjitdriver = JitDriver(greens = [], reds = ['y', 'res', 'x'])
@@ -125,7 +124,7 @@
res = self.meta_interp(f, [6, 7])
assert res == 1323
self.check_loop_count(1)
- self.check_loops(int_mul_ovf=1)
+ self.check_resops(int_mul_ovf=3)
def test_loop_invariant_mul1(self):
myjitdriver = JitDriver(greens = [], reds = ['y', 'res', 'x'])
@@ -140,9 +139,9 @@
res = self.meta_interp(f, [6, 7])
assert res == 252
self.check_loop_count(1)
- self.check_loops({'guard_true': 1,
- 'int_add': 1, 'int_sub': 1, 'int_gt': 1,
- 'jump': 1})
+ self.check_resops({'jump': 2, 'int_gt': 2, 'int_add': 2,
+ 'int_mul': 1, 'guard_true': 2, 'int_sub': 2})
+
def test_loop_invariant_mul_ovf(self):
myjitdriver = JitDriver(greens = [], reds = ['y', 'res', 'x'])
@@ -158,10 +157,10 @@
res = self.meta_interp(f, [6, 7])
assert res == 308
self.check_loop_count(1)
- self.check_loops({'guard_true': 1,
- 'int_add': 2, 'int_sub': 1, 'int_gt': 1,
- 'int_lshift': 1,
- 'jump': 1})
+ self.check_resops({'jump': 2, 'int_lshift': 2, 'int_gt': 2,
+ 'int_mul_ovf': 1, 'int_add': 4,
+ 'guard_true': 2, 'guard_no_overflow': 1,
+ 'int_sub': 2})
def test_loop_invariant_mul_bridge1(self):
myjitdriver = JitDriver(greens = [], reds = ['y', 'res', 'x'])
@@ -194,11 +193,9 @@
res = self.meta_interp(f, [6, 32])
assert res == 1167
self.check_loop_count(3)
- self.check_loops({'int_add': 3, 'int_lt': 2,
- 'int_sub': 2, 'guard_false': 1,
- 'jump': 2,
- 'int_gt': 1, 'guard_true': 2})
-
+ self.check_resops({'int_lt': 3, 'int_gt': 2, 'int_add': 5,
+ 'guard_true': 3, 'int_sub': 4, 'jump': 4,
+ 'int_mul': 2, 'guard_false': 2})
def test_loop_invariant_mul_bridge_maintaining2(self):
myjitdriver = JitDriver(greens = [], reds = ['y', 'res', 'x'])
@@ -216,10 +213,9 @@
res = self.meta_interp(f, [6, 32])
assert res == 1692
self.check_loop_count(3)
- self.check_loops({'int_add': 3, 'int_lt': 2,
- 'int_sub': 2, 'guard_false': 1,
- 'jump': 2,
- 'int_gt': 1, 'guard_true': 2})
+ self.check_resops({'int_lt': 3, 'int_gt': 2, 'int_add': 5,
+ 'guard_true': 3, 'int_sub': 4, 'jump': 4,
+ 'int_mul': 2, 'guard_false': 2})
def test_loop_invariant_mul_bridge_maintaining3(self):
myjitdriver = JitDriver(greens = [], reds = ['y', 'res', 'x', 'm'])
@@ -237,10 +233,9 @@
res = self.meta_interp(f, [6, 32, 16])
assert res == 1692
self.check_loop_count(3)
- self.check_loops({'int_add': 2, 'int_lt': 1,
- 'int_sub': 2, 'guard_false': 1,
- 'jump': 2, 'int_mul': 1,
- 'int_gt': 2, 'guard_true': 2})
+ self.check_resops({'int_lt': 2, 'int_gt': 4, 'guard_false': 2,
+ 'guard_true': 4, 'int_sub': 4, 'jump': 4,
+ 'int_mul': 3, 'int_add': 4})
def test_loop_invariant_intbox(self):
myjitdriver = JitDriver(greens = [], reds = ['y', 'res', 'x'])
@@ -261,9 +256,9 @@
res = self.meta_interp(f, [6, 7])
assert res == 252
self.check_loop_count(1)
- self.check_loops({'guard_true': 1,
- 'int_add': 1, 'int_sub': 1, 'int_gt': 1,
- 'jump': 1})
+ self.check_resops({'jump': 2, 'int_gt': 2, 'int_add': 2,
+ 'getfield_gc_pure': 1, 'int_mul': 1,
+ 'guard_true': 2, 'int_sub': 2})
def test_loops_are_transient(self):
import gc, weakref
@@ -381,7 +376,7 @@
assert res == 0
# CALL_PURE is recorded in the history, but turned into a CALL
# by optimizeopt.py
- self.check_loops(int_sub=0, call=1, call_pure=0)
+ self.check_resops(call_pure=0, call=2, int_sub=0)
def test_constfold_call_elidable(self):
myjitdriver = JitDriver(greens = ['m'], reds = ['n'])
@@ -397,7 +392,7 @@
res = self.meta_interp(f, [21, 5])
assert res == -1
# the CALL_PURE is constant-folded away by optimizeopt.py
- self.check_loops(int_sub=1, call=0, call_pure=0)
+ self.check_resops(call_pure=0, call=0, int_sub=2)
def test_constfold_call_elidable_2(self):
myjitdriver = JitDriver(greens = ['m'], reds = ['n'])
@@ -417,7 +412,7 @@
res = self.meta_interp(f, [21, 5])
assert res == -1
# the CALL_PURE is constant-folded away by optimizeopt.py
- self.check_loops(int_sub=1, call=0, call_pure=0)
+ self.check_resops(call_pure=0, call=0, int_sub=2)
def test_elidable_function_returning_object(self):
myjitdriver = JitDriver(greens = ['m'], reds = ['n'])
@@ -442,7 +437,7 @@
res = self.meta_interp(f, [21, 5])
assert res == -1
# the CALL_PURE is constant-folded away by optimizeopt.py
- self.check_loops(int_sub=1, call=0, call_pure=0, getfield_gc=0)
+ self.check_resops(call_pure=0, call=0, getfield_gc=1, int_sub=2)
def test_elidable_raising(self):
myjitdriver = JitDriver(greens = ['m'], reds = ['n'])
@@ -463,12 +458,12 @@
res = self.meta_interp(f, [22, 6])
assert res == -3
# the CALL_PURE is constant-folded away during tracing
- self.check_loops(int_sub=1, call=0, call_pure=0)
+ self.check_resops(call_pure=0, call=0, int_sub=2)
#
res = self.meta_interp(f, [22, -5])
assert res == 0
# raises: becomes CALL and is not constant-folded away
- self.check_loops(int_sub=1, call=1, call_pure=0)
+ self.check_resops(call_pure=0, call=2, int_sub=2)
def test_elidable_raising_2(self):
myjitdriver = JitDriver(greens = ['m'], reds = ['n'])
@@ -489,12 +484,12 @@
res = self.meta_interp(f, [22, 6])
assert res == -3
# the CALL_PURE is constant-folded away by optimizeopt.py
- self.check_loops(int_sub=1, call=0, call_pure=0)
+ self.check_resops(call_pure=0, call=0, int_sub=2)
#
res = self.meta_interp(f, [22, -5])
assert res == 0
# raises: becomes CALL and is not constant-folded away
- self.check_loops(int_sub=1, call=1, call_pure=0)
+ self.check_resops(call_pure=0, call=2, int_sub=2)
def test_constant_across_mp(self):
myjitdriver = JitDriver(greens = [], reds = ['n'])
@@ -533,7 +528,7 @@
policy = StopAtXPolicy(externfn)
res = self.meta_interp(f, [31], policy=policy)
assert res == 42
- self.check_loops(int_mul=1, int_mod=0)
+ self.check_resops(int_mul=2, int_mod=0)
def test_we_are_jitted(self):
myjitdriver = JitDriver(greens = [], reds = ['y'])
@@ -835,7 +830,7 @@
return n
res = self.meta_interp(f, [20, 1, 2])
assert res == 0
- self.check_loops(call=0)
+ self.check_resops(call=0)
def test_abs(self):
myjitdriver = JitDriver(greens = [], reds = ['i', 't'])
@@ -865,9 +860,8 @@
res = self.meta_interp(f, [6, 7])
assert res == 42.0
self.check_loop_count(1)
- self.check_loops({'guard_true': 1,
- 'float_add': 1, 'float_sub': 1, 'float_gt': 1,
- 'jump': 1})
+ self.check_resops({'jump': 2, 'float_gt': 2, 'float_add': 2,
+ 'float_sub': 2, 'guard_true': 2})
def test_print(self):
myjitdriver = JitDriver(greens = [], reds = ['n'])
@@ -1038,7 +1032,7 @@
return x
res = self.meta_interp(f, [20], enable_opts='')
assert res == f(20)
- self.check_loops(call=0)
+ self.check_resops(call=0)
def test_zerodivisionerror(self):
# test the case of exception-raising operation that is not delegated
@@ -1351,7 +1345,7 @@
res = self.meta_interp(f, [6, 7])
assert res == 42
self.check_loop_count(1)
- self.check_loops(call=1)
+ self.check_resops(call=2)
def test_merge_guardclass_guardvalue(self):
from pypy.rlib.objectmodel import instantiate
@@ -1378,8 +1372,7 @@
return x
res = self.meta_interp(f, [299], listops=True)
assert res == f(299)
- self.check_loops(guard_class=0, guard_value=3)
- self.check_loops(guard_class=0, guard_value=6, everywhere=True)
+ self.check_resops(guard_class=0, guard_value=6)
def test_merge_guardnonnull_guardclass(self):
from pypy.rlib.objectmodel import instantiate
@@ -1407,11 +1400,9 @@
return x
res = self.meta_interp(f, [299], listops=True)
assert res == f(299)
- self.check_loops(guard_class=0, guard_nonnull=2,
- guard_nonnull_class=2, guard_isnull=1)
- self.check_loops(guard_class=0, guard_nonnull=4,
- guard_nonnull_class=4, guard_isnull=2,
- everywhere=True)
+ self.check_resops(guard_class=0, guard_nonnull=4,
+ guard_nonnull_class=4, guard_isnull=2)
+
def test_merge_guardnonnull_guardvalue(self):
from pypy.rlib.objectmodel import instantiate
@@ -1438,11 +1429,9 @@
return x
res = self.meta_interp(f, [299], listops=True)
assert res == f(299)
- self.check_loops(guard_class=0, guard_nonnull=2, guard_value=2,
- guard_nonnull_class=0, guard_isnull=1)
- self.check_loops(guard_class=0, guard_nonnull=4, guard_value=4,
- guard_nonnull_class=0, guard_isnull=2,
- everywhere=True)
+ self.check_resops(guard_value=4, guard_class=0, guard_nonnull=4,
+ guard_nonnull_class=0, guard_isnull=2)
+
def test_merge_guardnonnull_guardvalue_2(self):
from pypy.rlib.objectmodel import instantiate
@@ -1469,11 +1458,9 @@
return x
res = self.meta_interp(f, [299], listops=True)
assert res == f(299)
- self.check_loops(guard_class=0, guard_nonnull=2, guard_value=2,
- guard_nonnull_class=0, guard_isnull=1)
- self.check_loops(guard_class=0, guard_nonnull=4, guard_value=4,
- guard_nonnull_class=0, guard_isnull=2,
- everywhere=True)
+ self.check_resops(guard_value=4, guard_class=0, guard_nonnull=4,
+ guard_nonnull_class=0, guard_isnull=2)
+
def test_merge_guardnonnull_guardclass_guardvalue(self):
from pypy.rlib.objectmodel import instantiate
@@ -1503,11 +1490,9 @@
return x
res = self.meta_interp(f, [399], listops=True)
assert res == f(399)
- self.check_loops(guard_class=0, guard_nonnull=3, guard_value=3,
- guard_nonnull_class=0, guard_isnull=1)
- self.check_loops(guard_class=0, guard_nonnull=6, guard_value=6,
- guard_nonnull_class=0, guard_isnull=2,
- everywhere=True)
+ self.check_resops(guard_class=0, guard_nonnull=6, guard_value=6,
+ guard_nonnull_class=0, guard_isnull=2)
+
def test_residual_call_doesnt_lose_info(self):
myjitdriver = JitDriver(greens = [], reds = ['x', 'y', 'l'])
@@ -1533,8 +1518,7 @@
y.v = g(y.v) - y.v/y.v + lc/l[0] - 1
return y.v
res = self.meta_interp(f, [20], listops=True)
- self.check_loops(getfield_gc=0, getarrayitem_gc=0)
- self.check_loops(getfield_gc=1, getarrayitem_gc=0, everywhere=True)
+ self.check_resops(getarrayitem_gc=0, getfield_gc=1)
def test_guard_isnull_nonnull(self):
myjitdriver = JitDriver(greens = [], reds = ['x', 'res'])
@@ -1562,7 +1546,7 @@
return res
res = self.meta_interp(f, [21])
assert res == 42
- self.check_loops(guard_nonnull=1, guard_isnull=1)
+ self.check_resops(guard_nonnull=2, guard_isnull=2)
def test_loop_invariant1(self):
myjitdriver = JitDriver(greens = [], reds = ['x', 'res'])
@@ -1589,8 +1573,7 @@
return res
res = self.meta_interp(g, [21])
assert res == 3 * 21
- self.check_loops(call=0)
- self.check_loops(call=1, everywhere=True)
+ self.check_resops(call=1)
def test_bug_optimizeopt_mutates_ops(self):
myjitdriver = JitDriver(greens = [], reds = ['x', 'res', 'const', 'a'])
@@ -1710,7 +1693,7 @@
return x
res = self.meta_interp(f, [8])
assert res == 0
- self.check_loops(jit_debug=2)
+ self.check_resops(jit_debug=4)
def test_assert_green(self):
def f(x, promote_flag):
@@ -1752,9 +1735,10 @@
res = self.meta_interp(g, [6, 7])
assert res == 6*8 + 6**8
self.check_loop_count(5)
- self.check_loops({'guard_true': 2,
- 'int_add': 1, 'int_mul': 1, 'int_sub': 2,
- 'int_gt': 2, 'jump': 2})
+ self.check_resops({'guard_class': 2, 'int_gt': 4,
+ 'getfield_gc': 4, 'guard_true': 4,
+ 'int_sub': 4, 'jump': 4, 'int_mul': 2,
+ 'int_add': 2})
def test_multiple_specialied_versions_array(self):
myjitdriver = JitDriver(greens = [], reds = ['idx', 'y', 'x', 'res',
@@ -1795,7 +1779,7 @@
res = self.meta_interp(g, [6, 14])
assert res == g(6, 14)
self.check_loop_count(9)
- self.check_loops(getarrayitem_gc=8, everywhere=True)
+ self.check_resops(getarrayitem_gc=8)
def test_multiple_specialied_versions_bridge(self):
myjitdriver = JitDriver(greens = [], reds = ['y', 'x', 'z', 'res'])
@@ -1983,8 +1967,8 @@
res = self.meta_interp(g, [3, 23])
assert res == 7068153
self.check_loop_count(7)
- self.check_loops(guard_true=4, guard_class=0, int_add=2, int_mul=2,
- guard_false=2)
+ self.check_resops(guard_true=6, guard_class=2, int_mul=3,
+ int_add=3, guard_false=3)
def test_dont_trace_every_iteration(self):
myjitdriver = JitDriver(greens = [], reds = ['a', 'b', 'i', 'sa'])
@@ -2228,27 +2212,27 @@
return sa
assert self.meta_interp(f1, [5, 5]) == 50
- self.check_loops(int_rshift=0, everywhere=True)
+ self.check_resops(int_rshift=0)
for f in (f1, f2):
assert self.meta_interp(f, [5, 6]) == 50
- self.check_loops(int_rshift=3, everywhere=True)
+ self.check_resops(int_rshift=3)
assert self.meta_interp(f, [10, 5]) == 100
- self.check_loops(int_rshift=3, everywhere=True)
+ self.check_resops(int_rshift=3)
assert self.meta_interp(f, [10, 6]) == 100
- self.check_loops(int_rshift=3, everywhere=True)
+ self.check_resops(int_rshift=3)
assert self.meta_interp(f, [5, 31]) == 0
- self.check_loops(int_rshift=3, everywhere=True)
+ self.check_resops(int_rshift=3)
bigval = 1
while (bigval << 3).__class__ is int:
bigval = bigval << 1
assert self.meta_interp(f, [bigval, 5]) == 0
- self.check_loops(int_rshift=3, everywhere=True)
+ self.check_resops(int_rshift=3)
def test_overflowing_shift_neg(self):
myjitdriver = JitDriver(greens = [], reds = ['a', 'b', 'n', 'sa'])
@@ -2273,27 +2257,27 @@
return sa
assert self.meta_interp(f1, [-5, 5]) == -50
- self.check_loops(int_rshift=0, everywhere=True)
+ self.check_resops(int_rshift=0)
for f in (f1, f2):
assert self.meta_interp(f, [-5, 6]) == -50
- self.check_loops(int_rshift=3, everywhere=True)
+ self.check_resops(int_rshift=3)
assert self.meta_interp(f, [-10, 5]) == -100
- self.check_loops(int_rshift=3, everywhere=True)
+ self.check_resops(int_rshift=3)
assert self.meta_interp(f, [-10, 6]) == -100
- self.check_loops(int_rshift=3, everywhere=True)
+ self.check_resops(int_rshift=3)
assert self.meta_interp(f, [-5, 31]) == 0
- self.check_loops(int_rshift=3, everywhere=True)
+ self.check_resops(int_rshift=3)
bigval = 1
while (bigval << 3).__class__ is int:
bigval = bigval << 1
assert self.meta_interp(f, [bigval, 5]) == 0
- self.check_loops(int_rshift=3, everywhere=True)
+ self.check_resops(int_rshift=3)
def test_pure_op_not_to_be_propagated(self):
myjitdriver = JitDriver(greens = [], reds = ['n', 'sa'])
@@ -2433,8 +2417,7 @@
if counter > 10:
return 7
assert self.meta_interp(build, []) == 7
- self.check_loops(getfield_gc_pure=0)
- self.check_loops(getfield_gc_pure=2, everywhere=True)
+ self.check_resops(getfield_gc_pure=2)
def test_args_becomming_equal(self):
myjitdriver = JitDriver(greens = [], reds = ['n', 'i', 'sa', 'a', 'b'])
@@ -2567,7 +2550,7 @@
i += 1
return sa
assert self.meta_interp(f, [20]) == f(20)
- self.check_loops(int_gt=1, int_lt=2, int_ge=0, int_le=0)
+ self.check_resops(int_lt=4, int_le=0, int_ge=0, int_gt=2)
def test_intbounds_not_generalized1(self):
myjitdriver = JitDriver(greens = [], reds = ['n', 'i', 'sa'])
@@ -2584,7 +2567,8 @@
i += 1
return sa
assert self.meta_interp(f, [20]) == f(20)
- self.check_loops(int_gt=1, int_lt=3, int_ge=2, int_le=1)
+ self.check_resops(int_lt=6, int_le=2, int_ge=4, int_gt=3)
+
def test_intbounds_not_generalized2(self):
myjitdriver = JitDriver(greens = [], reds = ['n', 'i', 'sa', 'node'])
@@ -2604,7 +2588,7 @@
i += 1
return sa
assert self.meta_interp(f, [20]) == f(20)
- self.check_loops(int_gt=1, int_lt=2, int_ge=1, int_le=1)
+ self.check_resops(int_lt=4, int_le=3, int_ge=3, int_gt=2)
def test_retrace_limit1(self):
myjitdriver = JitDriver(greens = [], reds = ['n', 'i', 'sa', 'a'])
@@ -2858,7 +2842,7 @@
return a[0].intvalue
res = self.meta_interp(f, [100])
assert res == -2
- #self.check_loops(getarrayitem_gc=0, setarrayitem_gc=0) -- xxx?
+ self.check_resops(setarrayitem_gc=2, getarrayitem_gc=1)
def test_retrace_ending_up_retracing_another_loop(self):
@@ -2958,7 +2942,7 @@
i += 1
res = self.meta_interp(f, [32])
assert res == f(32)
- self.check_loops(arraylen_gc=2)
+ self.check_resops(arraylen_gc=3)
def test_ulonglong_mod(self):
myjitdriver = JitDriver(greens = [], reds = ['n', 'sa', 'i'])
@@ -3145,9 +3129,9 @@
a = A(a.i + 1)
self.meta_interp(f, [])
- self.check_loops(new_with_vtable=0)
+ self.check_resops(new_with_vtable=0)
self.meta_interp(f, [], enable_opts='')
- self.check_loops(new_with_vtable=1)
+ self.check_resops(new_with_vtable=1)
def test_two_loopinvariant_arrays1(self):
from pypy.rpython.lltypesystem import lltype, llmemory, rffi
@@ -3239,7 +3223,7 @@
return sa
res = self.meta_interp(f, [32])
assert res == f(32)
- self.check_loops(arraylen_gc=2, everywhere=True)
+ self.check_resops(arraylen_gc=2)
def test_release_gil_flush_heap_cache(self):
if sys.platform == "win32":
@@ -3276,7 +3260,7 @@
lock.release()
return n
res = self.meta_interp(f, [10, 1])
- self.check_loops(getfield_gc=2)
+ self.check_resops(getfield_gc=4)
assert res == f(10, 1)
def test_jit_merge_point_with_raw_pointer(self):
@@ -3340,10 +3324,10 @@
res = self.meta_interp(main, [0, 10, 2], enable_opts='')
assert res == main(0, 10, 2)
- self.check_loops(call=1)
+ self.check_resops(call=1)
res = self.meta_interp(main, [1, 10, 2], enable_opts='')
assert res == main(1, 10, 2)
- self.check_loops(call=0)
+ self.check_resops(call=0)
def test_look_inside_iff_virtual(self):
# There's no good reason for this to be look_inside_iff, but it's a test!
@@ -3368,10 +3352,10 @@
i += f(A(2), n)
res = self.meta_interp(main, [0], enable_opts='')
assert res == main(0)
- self.check_loops(call=1, getfield_gc=0)
+ self.check_resops(call=1, getfield_gc=0)
res = self.meta_interp(main, [1], enable_opts='')
assert res == main(1)
- self.check_loops(call=0, getfield_gc=0)
+ self.check_resops(call=0, getfield_gc=0)
def test_reuse_elidable_result(self):
driver = JitDriver(reds=['n', 's'], greens = [])
@@ -3384,10 +3368,9 @@
return s
res = self.meta_interp(main, [10])
assert res == main(10)
- self.check_loops({
- 'call': 1, 'guard_no_exception': 1, 'guard_true': 1, 'int_add': 2,
- 'int_gt': 1, 'int_sub': 1, 'strlen': 1, 'jump': 1,
- })
+ self.check_resops({'int_gt': 2, 'strlen': 2, 'guard_true': 2,
+ 'int_sub': 2, 'jump': 2, 'call': 2,
+ 'guard_no_exception': 2, 'int_add': 4})
def test_look_inside_iff_const_getarrayitem_gc_pure(self):
driver = JitDriver(greens=['unroll'], reds=['s', 'n'])
@@ -3419,10 +3402,10 @@
res = self.meta_interp(main, [0, 10])
assert res == main(0, 10)
# 2 calls, one for f() and one for char_mul
- self.check_loops(call=2)
+ self.check_resops(call=4)
res = self.meta_interp(main, [1, 10])
assert res == main(1, 10)
- self.check_loops(call=0)
+ self.check_resops(call=0)
def test_setarrayitem_followed_by_arraycopy(self):
myjitdriver = JitDriver(greens = [], reds = ['n', 'sa', 'x', 'y'])
@@ -3523,7 +3506,8 @@
res = self.meta_interp(f, [10])
assert res == 0
- self.check_loops({"int_sub": 1, "int_gt": 1, "guard_true": 1, "jump": 1})
+ self.check_resops({'jump': 2, 'guard_true': 2, 'int_gt': 2,
+ 'int_sub': 2})
def test_virtual_opaque_ptr(self):
myjitdriver = JitDriver(greens = [], reds = ["n"])
@@ -3542,7 +3526,9 @@
return n
res = self.meta_interp(f, [10])
assert res == 0
- self.check_loops({"int_sub": 1, "int_gt": 1, "guard_true": 1, "jump": 1})
+ self.check_resops({'jump': 2, 'guard_true': 2, 'int_gt': 2,
+ 'int_sub': 2})
+
def test_virtual_opaque_dict(self):
myjitdriver = JitDriver(greens = [], reds = ["n"])
@@ -3562,7 +3548,10 @@
return n
res = self.meta_interp(f, [10])
assert res == 0
- self.check_loops({"int_sub": 1, "int_gt": 1, "guard_true": 1, "jump": 1})
+ self.check_resops({'int_gt': 2, 'getfield_gc': 1, 'int_eq': 1,
+ 'guard_true': 2, 'int_sub': 2, 'jump': 2,
+ 'guard_false': 1})
+
def test_convert_from_SmallFunctionSetPBCRepr_to_FunctionsPBCRepr(self):
f1 = lambda n: n+1
diff --git a/pypy/jit/metainterp/test/test_del.py b/pypy/jit/metainterp/test/test_del.py
--- a/pypy/jit/metainterp/test/test_del.py
+++ b/pypy/jit/metainterp/test/test_del.py
@@ -20,12 +20,12 @@
n -= 1
return 42
self.meta_interp(f, [20])
- self.check_loops({'call': 2, # calls to a helper function
- 'guard_no_exception': 2, # follows the calls
- 'int_sub': 1,
- 'int_gt': 1,
- 'guard_true': 1,
- 'jump': 1})
+ self.check_resops({'call': 4, # calls to a helper function
+ 'guard_no_exception': 4, # follows the calls
+ 'int_sub': 2,
+ 'int_gt': 2,
+ 'guard_true': 2,
+ 'jump': 2})
def test_class_of_allocated(self):
myjitdriver = JitDriver(greens = [], reds = ['n', 'x'])
@@ -78,7 +78,7 @@
return 1
res = self.meta_interp(f, [20], enable_opts='')
assert res == 1
- self.check_loops(call=1) # for the case B(), but not for the case A()
+ self.check_resops(call=1) # for the case B(), but not for the case A()
class TestLLtype(DelTests, LLJitMixin):
@@ -103,7 +103,7 @@
break
return 42
self.meta_interp(f, [20])
- self.check_loops(getfield_raw=1, setfield_raw=1, call=0, call_pure=0)
+ self.check_resops(call_pure=0, setfield_raw=2, call=0, getfield_raw=2)
class TestOOtype(DelTests, OOJitMixin):
def setup_class(cls):
diff --git a/pypy/jit/metainterp/test/test_dict.py b/pypy/jit/metainterp/test/test_dict.py
--- a/pypy/jit/metainterp/test/test_dict.py
+++ b/pypy/jit/metainterp/test/test_dict.py
@@ -91,7 +91,7 @@
res1 = f(100)
res2 = self.meta_interp(f, [100], listops=True)
assert res1 == res2
- self.check_loops(int_mod=1) # the hash was traced and eq, but cached
+ self.check_resops(int_mod=2) # the hash was traced and eq, but cached
def test_dict_setdefault(self):
myjitdriver = JitDriver(greens = [], reds = ['total', 'dct'])
@@ -107,7 +107,7 @@
assert f(100) == 50
res = self.meta_interp(f, [100], listops=True)
assert res == 50
- self.check_loops(new=0, new_with_vtable=0)
+ self.check_resops(new=0, new_with_vtable=0)
def test_dict_as_counter(self):
myjitdriver = JitDriver(greens = [], reds = ['total', 'dct'])
@@ -128,7 +128,7 @@
assert f(100) == 50
res = self.meta_interp(f, [100], listops=True)
assert res == 50
- self.check_loops(int_mod=1) # key + eq, but cached
+ self.check_resops(int_mod=2) # key + eq, but cached
def test_repeated_lookup(self):
myjitdriver = JitDriver(greens = [], reds = ['n', 'd'])
@@ -153,12 +153,13 @@
res = self.meta_interp(f, [100], listops=True)
assert res == f(50)
- self.check_loops({"call": 5, "getfield_gc": 1, "getinteriorfield_gc": 1,
- "guard_false": 1, "guard_no_exception": 4,
- "guard_true": 1, "int_and": 1, "int_gt": 1,
- "int_is_true": 1, "int_sub": 1, "jump": 1,
- "new_with_vtable": 1, "new": 1, "new_array": 1,
- "setfield_gc": 3, })
+ self.check_resops({'new_array': 2, 'getfield_gc': 2,
+ 'guard_true': 2, 'jump': 2,
+ 'new_with_vtable': 2, 'getinteriorfield_gc': 2,
+ 'setfield_gc': 6, 'int_gt': 2, 'int_sub': 2,
+ 'call': 10, 'int_and': 2,
+ 'guard_no_exception': 8, 'new': 2,
+ 'guard_false': 2, 'int_is_true': 2})
class TestOOtype(DictTests, OOJitMixin):
diff --git a/pypy/jit/metainterp/test/test_exception.py b/pypy/jit/metainterp/test/test_exception.py
--- a/pypy/jit/metainterp/test/test_exception.py
+++ b/pypy/jit/metainterp/test/test_exception.py
@@ -35,10 +35,8 @@
return n
res = self.meta_interp(f, [10])
assert res == 0
- self.check_loops({'jump': 1,
- 'int_gt': 1, 'guard_true': 1,
- 'int_sub': 1})
-
+ self.check_resops({'jump': 2, 'guard_true': 2,
+ 'int_gt': 2, 'int_sub': 2})
def test_bridge_from_guard_exception(self):
myjitdriver = JitDriver(greens = [], reds = ['n'])
diff --git a/pypy/jit/metainterp/test/test_fficall.py b/pypy/jit/metainterp/test/test_fficall.py
--- a/pypy/jit/metainterp/test/test_fficall.py
+++ b/pypy/jit/metainterp/test/test_fficall.py
@@ -67,23 +67,23 @@
'byval': False}
supported = all(d[check] for check in jitif)
if supported:
- self.check_loops(
- call_release_gil=1, # a CALL_RELEASE_GIL, and no other CALLs
+ self.check_resops(
+ call_release_gil=2, # a CALL_RELEASE_GIL, and no other CALLs
call=0,
call_may_force=0,
- guard_no_exception=1,
- guard_not_forced=1,
- int_add=1,
- int_lt=1,
- guard_true=1,
- jump=1)
+ guard_no_exception=2,
+ guard_not_forced=2,
+ int_add=2,
+ int_lt=2,
+ guard_true=2,
+ jump=2)
else:
- self.check_loops(
+ self.check_resops(
call_release_gil=0, # no CALL_RELEASE_GIL
- int_add=1,
- int_lt=1,
- guard_true=1,
- jump=1)
+ int_add=2,
+ int_lt=2,
+ guard_true=2,
+ jump=2)
return res
def test_byval_result(self):
@@ -144,10 +144,8 @@
return result_point[0].x * result_point[0].y
assert self.meta_interp(main, [10]) == main(10) == 9000
- self.check_loops({"int_add": 3, "jump": 1, "int_lt": 1, "guard_true": 1,
- "getinteriorfield_raw": 4, "setinteriorfield_raw": 2
- })
-
+ self.check_resops({'jump': 2, 'int_lt': 2, 'setinteriorfield_raw': 4,
+ 'getinteriorfield_raw': 8, 'int_add': 6, 'guard_true': 2})
class TestFfiCall(FfiCallTests, LLJitMixin):
supports_all = False
@@ -156,4 +154,4 @@
supports_all = True # supports_{floats,longlong,singlefloats}
class TestFfiLookup(FfiLookupTests, LLJitMixin):
- pass
\ No newline at end of file
+ pass
diff --git a/pypy/jit/metainterp/test/test_greenfield.py b/pypy/jit/metainterp/test/test_greenfield.py
--- a/pypy/jit/metainterp/test/test_greenfield.py
+++ b/pypy/jit/metainterp/test/test_greenfield.py
@@ -25,7 +25,7 @@
res = self.meta_interp(g, [7])
assert res == -2
self.check_loop_count(2)
- self.check_loops(guard_value=0)
+ self.check_resops(guard_value=0)
def test_green_field_2(self):
myjitdriver = JitDriver(greens=['ctx.x'], reds=['ctx'])
@@ -50,7 +50,7 @@
res = self.meta_interp(g, [7])
assert res == -22
self.check_loop_count(6)
- self.check_loops(guard_value=0)
+ self.check_resops(guard_value=0)
class TestLLtypeGreenFieldsTests(GreenFieldsTests, LLJitMixin):
diff --git a/pypy/jit/metainterp/test/test_jitdriver.py b/pypy/jit/metainterp/test/test_jitdriver.py
--- a/pypy/jit/metainterp/test/test_jitdriver.py
+++ b/pypy/jit/metainterp/test/test_jitdriver.py
@@ -88,7 +88,7 @@
assert res == loop2(4, 40)
# we expect only one int_sub, corresponding to the single
# compiled instance of loop1()
- self.check_loops(int_sub=1)
+ self.check_resops(int_sub=2)
# the following numbers are not really expectations of the test
# itself, but just the numbers that we got after looking carefully
# at the generated machine code
@@ -154,7 +154,7 @@
res = self.meta_interp(loop2, [4, 40], repeat=7, inline=True)
assert res == loop2(4, 40)
# we expect no int_sub, but a residual call
- self.check_loops(int_sub=0, call=1)
+ self.check_resops(call=2, int_sub=0)
def test_multiple_jits_trace_too_long(self):
myjitdriver1 = JitDriver(greens=["n"], reds=["i", "box"])
diff --git a/pypy/jit/metainterp/test/test_list.py b/pypy/jit/metainterp/test/test_list.py
--- a/pypy/jit/metainterp/test/test_list.py
+++ b/pypy/jit/metainterp/test/test_list.py
@@ -6,8 +6,8 @@
class ListTests:
def check_all_virtualized(self):
- self.check_loops(new_array=0, setarrayitem_gc=0, getarrayitem_gc=0,
- arraylen_gc=0)
+ self.check_resops(setarrayitem_gc=0, new_array=0, arraylen_gc=0,
+ getarrayitem_gc=0)
def test_simple_array(self):
jitdriver = JitDriver(greens = [], reds = ['n'])
@@ -20,7 +20,7 @@
return n
res = self.meta_interp(f, [10], listops=True)
assert res == 0
- self.check_loops(int_sub=1)
+ self.check_resops(int_sub=2)
self.check_all_virtualized()
def test_list_pass_around(self):
@@ -56,7 +56,8 @@
res = self.meta_interp(f, [10], listops=True)
assert res == f(10)
# one setitem should be gone by now
- self.check_loops(call=1, setarrayitem_gc=2, getarrayitem_gc=1)
+ self.check_resops(setarrayitem_gc=4, getarrayitem_gc=2, call=2)
+
def test_ll_fixed_setitem_fast(self):
jitdriver = JitDriver(greens = [], reds = ['n', 'l'])
@@ -93,7 +94,7 @@
res = self.meta_interp(f, [10], listops=True)
assert res == f(10)
- self.check_loops(setarrayitem_gc=0, getarrayitem_gc=0, call=0)
+ self.check_resops(setarrayitem_gc=0, call=0, getarrayitem_gc=0)
def test_vlist_alloc_and_set(self):
# the check_loops fails, because [non-null] * n is not supported yet
@@ -141,7 +142,7 @@
res = self.meta_interp(f, [5], listops=True)
assert res == 7
- self.check_loops(call=0)
+ self.check_resops(call=0)
def test_fold_getitem_1(self):
jitdriver = JitDriver(greens = ['pc', 'n', 'l'], reds = ['total'])
@@ -161,7 +162,7 @@
res = self.meta_interp(f, [4], listops=True)
assert res == f(4)
- self.check_loops(call=0)
+ self.check_resops(call=0)
def test_fold_getitem_2(self):
jitdriver = JitDriver(greens = ['pc', 'n', 'l'], reds = ['total', 'x'])
@@ -186,7 +187,7 @@
res = self.meta_interp(f, [4], listops=True)
assert res == f(4)
- self.check_loops(call=0, getfield_gc=0)
+ self.check_resops(call=0, getfield_gc=0)
def test_fold_indexerror(self):
jitdriver = JitDriver(greens = [], reds = ['total', 'n', 'lst'])
@@ -206,7 +207,7 @@
res = self.meta_interp(f, [15], listops=True)
assert res == f(15)
- self.check_loops(guard_exception=0)
+ self.check_resops(guard_exception=0)
def test_virtual_resize(self):
jitdriver = JitDriver(greens = [], reds = ['n', 's'])
@@ -224,9 +225,8 @@
return s
res = self.meta_interp(f, [15], listops=True)
assert res == f(15)
- self.check_loops({"int_add": 1, "int_sub": 1, "int_gt": 1,
- "guard_true": 1, "jump": 1})
-
+ self.check_resops({'jump': 2, 'int_gt': 2, 'int_add': 2,
+ 'guard_true': 2, 'int_sub': 2})
class TestOOtype(ListTests, OOJitMixin):
pass
@@ -258,4 +258,4 @@
assert res == f(37)
# There is the one actual field on a, plus several fields on the list
# itself
- self.check_loops(getfield_gc=10, everywhere=True)
+ self.check_resops(getfield_gc=10)
diff --git a/pypy/jit/metainterp/test/test_loop.py b/pypy/jit/metainterp/test/test_loop.py
--- a/pypy/jit/metainterp/test/test_loop.py
+++ b/pypy/jit/metainterp/test/test_loop.py
@@ -60,7 +60,8 @@
assert res == f(6, 13)
self.check_loop_count(1)
if self.enable_opts:
- self.check_loops(getfield_gc = 0, setfield_gc = 1)
+ self.check_resops(setfield_gc=2, getfield_gc=0)
+
def test_loop_with_two_paths(self):
from pypy.rpython.lltypesystem import lltype
@@ -180,7 +181,10 @@
assert res == 42
self.check_loop_count(1)
# the 'int_eq' and following 'guard' should be constant-folded
- self.check_loops(int_eq=0, guard_true=1, guard_false=0)
+ if 'unroll' in self.enable_opts:
+ self.check_resops(int_eq=0, guard_true=2, guard_false=0)
+ else:
+ self.check_resops(int_eq=0, guard_true=1, guard_false=0)
if self.basic:
found = 0
for op in get_stats().loops[0]._all_operations():
@@ -643,8 +647,12 @@
res = self.meta_interp(main_interpreter_loop, [1])
assert res == 102
self.check_loop_count(1)
- self.check_loops({'int_add' : 3, 'int_gt' : 1,
- 'guard_false' : 1, 'jump' : 1})
+ if 'unroll' in self.enable_opts:
+ self.check_resops({'int_add' : 6, 'int_gt' : 2,
+ 'guard_false' : 2, 'jump' : 2})
+ else:
+ self.check_resops({'int_add' : 3, 'int_gt' : 1,
+ 'guard_false' : 1, 'jump' : 1})
def test_automatic_promotion(self):
myjitdriver = JitDriver(greens = ['i'],
@@ -686,7 +694,7 @@
self.check_loop_count(1)
# These loops do different numbers of ops based on which optimizer we
# are testing with.
- self.check_loops(self.automatic_promotion_result)
+ self.check_resops(self.automatic_promotion_result)
def test_can_enter_jit_outside_main_loop(self):
myjitdriver = JitDriver(greens=[], reds=['i', 'j', 'a'])
diff --git a/pypy/jit/metainterp/test/test_loop_unroll.py b/pypy/jit/metainterp/test/test_loop_unroll.py
--- a/pypy/jit/metainterp/test/test_loop_unroll.py
+++ b/pypy/jit/metainterp/test/test_loop_unroll.py
@@ -8,7 +8,8 @@
enable_opts = ALL_OPTS_NAMES
automatic_promotion_result = {
- 'int_add' : 3, 'int_gt' : 1, 'guard_false' : 1, 'jump' : 1,
+ 'int_gt': 2, 'guard_false': 2, 'jump': 2, 'int_add': 6,
+ 'guard_value': 1
}
# ====> test_loop.py
diff --git a/pypy/jit/metainterp/test/test_quasiimmut.py b/pypy/jit/metainterp/test/test_quasiimmut.py
--- a/pypy/jit/metainterp/test/test_quasiimmut.py
+++ b/pypy/jit/metainterp/test/test_quasiimmut.py
@@ -73,8 +73,7 @@
#
res = self.meta_interp(f, [100, 7])
assert res == 700
- self.check_loops(guard_not_invalidated=2, getfield_gc=0,
- everywhere=True)
+ self.check_resops(guard_not_invalidated=2, getfield_gc=0)
#
from pypy.jit.metainterp.warmspot import get_stats
loops = get_stats().loops
@@ -103,7 +102,7 @@
assert f(100, 7) == 721
res = self.meta_interp(f, [100, 7])
assert res == 721
- self.check_loops(guard_not_invalidated=0, getfield_gc=1)
+ self.check_resops(guard_not_invalidated=0, getfield_gc=3)
#
from pypy.jit.metainterp.warmspot import get_stats
loops = get_stats().loops
@@ -134,8 +133,7 @@
#
res = self.meta_interp(f, [100, 7])
assert res == 700
- self.check_loops(guard_not_invalidated=2, getfield_gc=0,
- everywhere=True)
+ self.check_resops(guard_not_invalidated=2, getfield_gc=0)
def test_change_during_tracing_1(self):
myjitdriver = JitDriver(greens=['foo'], reds=['x', 'total'])
@@ -160,7 +158,7 @@
assert f(100, 7) == 721
res = self.meta_interp(f, [100, 7])
assert res == 721
- self.check_loops(guard_not_invalidated=0, getfield_gc=1)
+ self.check_resops(guard_not_invalidated=0, getfield_gc=2)
def test_change_during_tracing_2(self):
myjitdriver = JitDriver(greens=['foo'], reds=['x', 'total'])
@@ -186,7 +184,7 @@
assert f(100, 7) == 700
res = self.meta_interp(f, [100, 7])
assert res == 700
- self.check_loops(guard_not_invalidated=0, getfield_gc=1)
+ self.check_resops(guard_not_invalidated=0, getfield_gc=2)
def test_change_invalidate_reentering(self):
myjitdriver = JitDriver(greens=['foo'], reds=['x', 'total'])
@@ -212,7 +210,7 @@
assert g(100, 7) == 700707
res = self.meta_interp(g, [100, 7])
assert res == 700707
- self.check_loops(guard_not_invalidated=2, getfield_gc=0)
+ self.check_resops(guard_not_invalidated=4, getfield_gc=0)
def test_invalidate_while_running(self):
jitdriver = JitDriver(greens=['foo'], reds=['i', 'total'])
@@ -324,8 +322,8 @@
assert f(100, 15) == 3009
res = self.meta_interp(f, [100, 15])
assert res == 3009
- self.check_loops(guard_not_invalidated=4, getfield_gc=0,
- call_may_force=0, guard_not_forced=0)
+ self.check_resops(guard_not_invalidated=8, guard_not_forced=0,
+ call_may_force=0, getfield_gc=0)
def test_list_simple_1(self):
myjitdriver = JitDriver(greens=['foo'], reds=['x', 'total'])
@@ -347,9 +345,8 @@
#
res = self.meta_interp(f, [100, 7])
assert res == 700
- self.check_loops(guard_not_invalidated=2, getfield_gc=0,
- getarrayitem_gc=0, getarrayitem_gc_pure=0,
- everywhere=True)
+ self.check_resops(getarrayitem_gc_pure=0, guard_not_invalidated=2,
+ getarrayitem_gc=0, getfield_gc=0)
#
from pypy.jit.metainterp.warmspot import get_stats
loops = get_stats().loops
@@ -385,9 +382,8 @@
#
res = self.meta_interp(f, [100, 7])
assert res == 714
- self.check_loops(guard_not_invalidated=2, getfield_gc=0,
- getarrayitem_gc=0, getarrayitem_gc_pure=0,
- arraylen_gc=0, everywhere=True)
+ self.check_resops(getarrayitem_gc_pure=0, guard_not_invalidated=2,
+ arraylen_gc=0, getarrayitem_gc=0, getfield_gc=0)
#
from pypy.jit.metainterp.warmspot import get_stats
loops = get_stats().loops
@@ -421,9 +417,8 @@
#
res = self.meta_interp(f, [100, 7])
assert res == 700
- self.check_loops(guard_not_invalidated=2, getfield_gc=0,
- getarrayitem_gc=0, getarrayitem_gc_pure=0,
- everywhere=True)
+ self.check_resops(guard_not_invalidated=2, getfield_gc=0,
+ getarrayitem_gc=0, getarrayitem_gc_pure=0)
#
from pypy.jit.metainterp.warmspot import get_stats
loops = get_stats().loops
@@ -460,9 +455,9 @@
assert f(100, 15) == 3009
res = self.meta_interp(f, [100, 15])
assert res == 3009
- self.check_loops(guard_not_invalidated=4, getfield_gc=0,
- getarrayitem_gc=0, getarrayitem_gc_pure=0,
- call_may_force=0, guard_not_forced=0)
+ self.check_resops(call_may_force=0, getfield_gc=0,
+ getarrayitem_gc_pure=0, guard_not_forced=0,
+ getarrayitem_gc=0, guard_not_invalidated=8)
def test_invalidated_loop_is_not_used_any_more_as_target(self):
myjitdriver = JitDriver(greens=['foo'], reds=['x'])
diff --git a/pypy/jit/metainterp/test/test_recursive.py b/pypy/jit/metainterp/test/test_recursive.py
--- a/pypy/jit/metainterp/test/test_recursive.py
+++ b/pypy/jit/metainterp/test/test_recursive.py
@@ -143,11 +143,11 @@
f = self.get_interpreter(codes)
assert self.meta_interp(f, [0, 0, 0], enable_opts='') == 42
- self.check_loops(int_add = 1, call_may_force = 1, call = 0)
+ self.check_resops(call_may_force=1, int_add=1, call=0)
assert self.meta_interp(f, [0, 0, 0], enable_opts='',
inline=True) == 42
- self.check_loops(int_add = 2, call_may_force = 0, call = 0,
- guard_no_exception = 0)
+ self.check_resops(call=0, int_add=2, call_may_force=0,
+ guard_no_exception=0)
def test_inline_jitdriver_check(self):
code = "021"
@@ -160,7 +160,7 @@
inline=True) == 42
# the call is fully inlined, because we jump to subcode[1], thus
# skipping completely the JUMP_BACK in subcode[0]
- self.check_loops(call_may_force = 0, call_assembler = 0, call = 0)
+ self.check_resops(call=0, call_may_force=0, call_assembler=0)
def test_guard_failure_in_inlined_function(self):
def p(pc, code):
@@ -491,10 +491,10 @@
return loop(100)
res = self.meta_interp(main, [0], enable_opts='', trace_limit=TRACE_LIMIT)
- self.check_loops(call_may_force=1, call=0)
+ self.check_resops(call=0, call_may_force=1)
res = self.meta_interp(main, [1], enable_opts='', trace_limit=TRACE_LIMIT)
- self.check_loops(call_may_force=0, call=0)
+ self.check_resops(call=0, call_may_force=0)
def test_trace_from_start(self):
def p(pc, code):
@@ -576,7 +576,7 @@
result += f('-c-----------l-', i+100)
self.meta_interp(g, [10], backendopt=True)
self.check_aborted_count(1)
- self.check_loops(call_assembler=1, call=0)
+ self.check_resops(call=0, call_assembler=2)
self.check_tree_loop_count(3)
def test_directly_call_assembler(self):
@@ -625,8 +625,7 @@
try:
compile.compile_tmp_callback = my_ctc
self.meta_interp(portal, [2, 5], inline=True)
- self.check_loops(call_assembler=2, call_may_force=0,
- everywhere=True)
+ self.check_resops(call_may_force=0, call_assembler=2)
finally:
compile.compile_tmp_callback = original_ctc
# check that we made a temporary callback
@@ -681,8 +680,7 @@
try:
compile.compile_tmp_callback = my_ctc
self.meta_interp(main, [2, 5], inline=True)
- self.check_loops(call_assembler=2, call_may_force=0,
- everywhere=True)
+ self.check_resops(call_may_force=0, call_assembler=2)
finally:
compile.compile_tmp_callback = original_ctc
# check that we made a temporary callback
@@ -1021,7 +1019,7 @@
res = self.meta_interp(portal, [2, 0], inline=True,
policy=StopAtXPolicy(residual))
assert res == portal(2, 0)
- self.check_loops(call_assembler=4, everywhere=True)
+ self.check_resops(call_assembler=4)
def test_inline_without_hitting_the_loop(self):
driver = JitDriver(greens = ['codeno'], reds = ['i'],
@@ -1045,7 +1043,7 @@
assert portal(0) == 70
res = self.meta_interp(portal, [0], inline=True)
assert res == 70
- self.check_loops(call_assembler=0)
+ self.check_resops(call_assembler=0)
def test_inline_with_hitting_the_loop_sometimes(self):
driver = JitDriver(greens = ['codeno'], reds = ['i', 'k'],
@@ -1071,7 +1069,7 @@
assert portal(0, 1) == 2095
res = self.meta_interp(portal, [0, 1], inline=True)
assert res == 2095
- self.check_loops(call_assembler=12, everywhere=True)
+ self.check_resops(call_assembler=12)
def test_inline_with_hitting_the_loop_sometimes_exc(self):
driver = JitDriver(greens = ['codeno'], reds = ['i', 'k'],
@@ -1109,7 +1107,7 @@
assert main(0, 1) == 2095
res = self.meta_interp(main, [0, 1], inline=True)
assert res == 2095
- self.check_loops(call_assembler=12, everywhere=True)
+ self.check_resops(call_assembler=12)
def test_handle_jitexception_in_portal(self):
# a test for _handle_jitexception_in_portal in blackhole.py
@@ -1238,7 +1236,7 @@
i += 1
self.meta_interp(portal, [0, 0, 0], inline=True)
- self.check_loops(call=0, call_may_force=0)
+ self.check_resops(call_may_force=0, call=0)
class TestLLtype(RecursiveTests, LLJitMixin):
pass
diff --git a/pypy/jit/metainterp/test/test_resume.py b/pypy/jit/metainterp/test/test_resume.py
--- a/pypy/jit/metainterp/test/test_resume.py
+++ b/pypy/jit/metainterp/test/test_resume.py
@@ -23,11 +23,11 @@
assert tag(-3, 2) == rffi.r_short(-3<<2|2)
assert tag((1<<13)-1, 3) == rffi.r_short(((1<<15)-1)|3)
assert tag(-1<<13, 3) == rffi.r_short((-1<<15)|3)
- py.test.raises(ValueError, tag, 3, 5)
- py.test.raises(ValueError, tag, 1<<13, 0)
- py.test.raises(ValueError, tag, (1<<13)+1, 0)
- py.test.raises(ValueError, tag, (-1<<13)-1, 0)
- py.test.raises(ValueError, tag, (-1<<13)-5, 0)
+ py.test.raises(AssertionError, tag, 3, 5)
+ py.test.raises(TagOverflow, tag, 1<<13, 0)
+ py.test.raises(TagOverflow, tag, (1<<13)+1, 0)
+ py.test.raises(TagOverflow, tag, (-1<<13)-1, 0)
+ py.test.raises(TagOverflow, tag, (-1<<13)-5, 0)
def test_untag():
assert untag(tag(3, 1)) == (3, 1)
@@ -1318,8 +1318,7 @@
assert rffi.cast(lltype.Signed, pf[1].fieldnum) == 1062
assert rffi.cast(lltype.Signed, pf[1].itemindex) == 2147483647
#
- from pypy.jit.metainterp.pyjitpl import SwitchToBlackhole
- py.test.raises(SwitchToBlackhole, modifier._add_pending_fields,
+ py.test.raises(TagOverflow, modifier._add_pending_fields,
[(array_a, 42, 63, 2147483648)])
def test_resume_reader_fields_and_arrayitems():
diff --git a/pypy/jit/metainterp/test/test_send.py b/pypy/jit/metainterp/test/test_send.py
--- a/pypy/jit/metainterp/test/test_send.py
+++ b/pypy/jit/metainterp/test/test_send.py
@@ -20,9 +20,8 @@
return c
res = self.meta_interp(f, [1])
assert res == 2
- self.check_loops({'jump': 1,
- 'int_sub': 1, 'int_gt' : 1,
- 'guard_true': 1}) # all folded away
+ self.check_resops({'jump': 2, 'guard_true': 2, 'int_gt': 2,
+ 'int_sub': 2}) # all folded away
def test_red_builtin_send(self):
myjitdriver = JitDriver(greens = [], reds = ['i', 'counter'])
@@ -41,12 +40,9 @@
return res
res = self.meta_interp(f, [1], policy=StopAtXPolicy(externfn))
assert res == 2
- if self.type_system == 'ootype':
- self.check_loops(call=1, oosend=1) # 'len' remains
- else:
- # 'len' becomes a getfield('num_items') for now in lltype,
- # which is itself encoded as a 'getfield_gc'
- self.check_loops(call=1, getfield_gc=1)
+ # 'len' becomes a getfield('num_items') for now in lltype,
+ # which is itself encoded as a 'getfield_gc'
+ self.check_resops(call=2, getfield_gc=2)
def test_send_to_single_target_method(self):
myjitdriver = JitDriver(greens = [], reds = ['i', 'counter'])
@@ -70,11 +66,10 @@
res = self.meta_interp(f, [1], policy=StopAtXPolicy(externfn),
backendopt=True)
assert res == 43
- self.check_loops({'call': 1, 'guard_no_exception': 1,
- 'getfield_gc': 1,
- 'int_add': 1,
- 'jump': 1, 'int_gt' : 1, 'guard_true' : 1,
- 'int_sub' : 1})
+ self.check_resops({'int_gt': 2, 'getfield_gc': 2,
+ 'guard_true': 2, 'int_sub': 2, 'jump': 2,
+ 'call': 2, 'guard_no_exception': 2,
+ 'int_add': 2})
def test_red_send_to_green_receiver(self):
myjitdriver = JitDriver(greens = ['i'], reds = ['counter', 'j'])
@@ -97,7 +92,7 @@
return res
res = self.meta_interp(f, [4, -1])
assert res == 145
- self.check_loops(int_add = 1, everywhere=True)
+ self.check_resops(int_add=1)
def test_oosend_base(self):
myjitdriver = JitDriver(greens = [], reds = ['x', 'y', 'w'])
@@ -132,7 +127,7 @@
assert res == 17
res = self.meta_interp(f, [4, 14])
assert res == 1404
- self.check_loops(guard_class=0, new_with_vtable=0, new=0)
+ self.check_resops(guard_class=1, new=0, new_with_vtable=0)
def test_three_receivers(self):
myjitdriver = JitDriver(greens = [], reds = ['y'])
@@ -205,8 +200,7 @@
# of the body in a single bigger loop with no failing guard except
# the final one.
self.check_loop_count(1)
- self.check_loops(guard_class=0,
- int_add=2, int_sub=2)
+ self.check_resops(guard_class=1, int_add=4, int_sub=4)
self.check_jumps(14)
def test_oosend_guard_failure_2(self):
@@ -247,8 +241,7 @@
res = self.meta_interp(f, [4, 28])
assert res == f(4, 28)
self.check_loop_count(1)
- self.check_loops(guard_class=0,
- int_add=2, int_sub=2)
+ self.check_resops(guard_class=1, int_add=4, int_sub=4)
self.check_jumps(14)
def test_oosend_different_initial_class(self):
@@ -285,8 +278,8 @@
# However, this doesn't match the initial value of 'w'.
# XXX This not completely easy to check...
self.check_loop_count(1)
- self.check_loops(int_add=0, int_lshift=1, guard_class=0,
- new_with_vtable=0, new=0)
+ self.check_resops(guard_class=1, new_with_vtable=0, int_lshift=2,
+ int_add=0, new=0)
def test_indirect_call_unknown_object_1(self):
myjitdriver = JitDriver(greens = [], reds = ['x', 'y'])
@@ -566,10 +559,7 @@
policy = StopAtXPolicy(new, A.foo.im_func, B.foo.im_func)
res = self.meta_interp(fn, [0, 20], policy=policy)
assert res == 42
- if self.type_system == 'ootype':
- self.check_loops(oosend=1)
- else:
- self.check_loops(call=1)
+ self.check_resops(call=2)
def test_residual_oosend_with_void(self):
@@ -597,10 +587,7 @@
policy = StopAtXPolicy(new, A.foo.im_func)
res = self.meta_interp(fn, [1, 20], policy=policy)
assert res == 41
- if self.type_system == 'ootype':
- self.check_loops(oosend=1)
- else:
- self.check_loops(call=1)
+ self.check_resops(call=2)
def test_constfold_pure_oosend(self):
myjitdriver = JitDriver(greens=[], reds = ['i', 'obj'])
@@ -621,10 +608,7 @@
policy = StopAtXPolicy(A.foo.im_func)
res = self.meta_interp(fn, [1, 20], policy=policy)
assert res == 42
- if self.type_system == 'ootype':
- self.check_loops(oosend=0)
- else:
- self.check_loops(call=0)
+ self.check_resops(call=0)
def test_generalize_loop(self):
myjitdriver = JitDriver(greens=[], reds = ['i', 'obj'])
diff --git a/pypy/jit/metainterp/test/test_slist.py b/pypy/jit/metainterp/test/test_slist.py
--- a/pypy/jit/metainterp/test/test_slist.py
+++ b/pypy/jit/metainterp/test/test_slist.py
@@ -76,7 +76,7 @@
return lst[i]
res = self.meta_interp(f, [21], listops=True)
assert res == f(21)
- self.check_loops(call=0)
+ self.check_resops(call=0)
def test_getitem_neg(self):
myjitdriver = JitDriver(greens = [], reds = ['i', 'n'])
@@ -92,7 +92,7 @@
return x
res = self.meta_interp(f, [-2], listops=True)
assert res == 41
- self.check_loops(call=0, guard_value=0)
+ self.check_resops(call=0, guard_value=0)
# we don't support resizable lists on ootype
#class TestOOtype(ListTests, OOJitMixin):
diff --git a/pypy/jit/metainterp/test/test_string.py b/pypy/jit/metainterp/test/test_string.py
--- a/pypy/jit/metainterp/test/test_string.py
+++ b/pypy/jit/metainterp/test/test_string.py
@@ -30,7 +30,7 @@
return i
res = self.meta_interp(f, [10, True, _str('h')], listops=True)
assert res == 5
- self.check_loops(**{self.CALL: 1, self.CALL_PURE: 0, 'everywhere': True})
+ self.check_resops(**{self.CALL: 1, self.CALL_PURE: 0})
def test_eq_folded(self):
_str = self._str
@@ -50,7 +50,7 @@
return i
res = self.meta_interp(f, [10, True, _str('h')], listops=True)
assert res == 5
- self.check_loops(**{self.CALL: 0, self.CALL_PURE: 0})
+ self.check_resops(**{self.CALL: 0, self.CALL_PURE: 0})
def test_newstr(self):
_str, _chr = self._str, self._chr
@@ -85,7 +85,7 @@
n -= 1
return 42
self.meta_interp(f, [6])
- self.check_loops(newstr=0, strsetitem=0, strlen=0,
+ self.check_resops(newstr=0, strsetitem=0, strlen=0,
newunicode=0, unicodesetitem=0, unicodelen=0)
def test_char2string_escape(self):
@@ -126,7 +126,7 @@
return total
res = self.meta_interp(f, [6])
assert res == 21
- self.check_loops(newstr=0, strgetitem=0, strsetitem=0, strlen=0,
+ self.check_resops(newstr=0, strgetitem=0, strsetitem=0, strlen=0,
newunicode=0, unicodegetitem=0, unicodesetitem=0,
unicodelen=0)
@@ -147,7 +147,7 @@
m -= 1
return 42
self.meta_interp(f, [6, 7])
- self.check_loops(newstr=0, strsetitem=0,
+ self.check_resops(newstr=0, strsetitem=0,
newunicode=0, unicodesetitem=0,
call=0, call_pure=0)
@@ -168,12 +168,11 @@
return 42
self.meta_interp(f, [6, 7])
if _str is str:
- self.check_loops(newstr=1, strsetitem=0, copystrcontent=2,
- call=1, call_pure=0) # escape
+ self.check_resops(call_pure=0, copystrcontent=4,
+ strsetitem=0, call=2, newstr=2)
else:
- self.check_loops(newunicode=1, unicodesetitem=0,
- copyunicodecontent=2,
- call=1, call_pure=0) # escape
+ self.check_resops(call_pure=0, unicodesetitem=0, call=2,
+ copyunicodecontent=4, newunicode=2)
def test_strconcat_escape_str_char(self):
_str, _chr = self._str, self._chr
@@ -192,12 +191,11 @@
return 42
self.meta_interp(f, [6, 7])
if _str is str:
- self.check_loops(newstr=1, strsetitem=1, copystrcontent=1,
- call=1, call_pure=0) # escape
+ self.check_resops(call_pure=0, copystrcontent=2, strsetitem=2,
+ call=2, newstr=2)
else:
- self.check_loops(newunicode=1, unicodesetitem=1,
- copyunicodecontent=1,
- call=1, call_pure=0) # escape
+ self.check_resops(call_pure=0, unicodesetitem=2, call=2,
+ copyunicodecontent=2, newunicode=2)
def test_strconcat_escape_char_str(self):
_str, _chr = self._str, self._chr
@@ -216,12 +214,11 @@
return 42
self.meta_interp(f, [6, 7])
if _str is str:
- self.check_loops(newstr=1, strsetitem=1, copystrcontent=1,
- call=1, call_pure=0) # escape
+ self.check_resops(call_pure=0, copystrcontent=2,
+ strsetitem=2, call=2, newstr=2)
else:
- self.check_loops(newunicode=1, unicodesetitem=1,
- copyunicodecontent=1,
- call=1, call_pure=0) # escape
+ self.check_resops(call_pure=0, unicodesetitem=2, call=2,
+ copyunicodecontent=2, newunicode=2)
def test_strconcat_escape_char_char(self):
_str, _chr = self._str, self._chr
@@ -239,12 +236,11 @@
return 42
self.meta_interp(f, [6, 7])
if _str is str:
- self.check_loops(newstr=1, strsetitem=2, copystrcontent=0,
- call=1, call_pure=0) # escape
+ self.check_resops(call_pure=0, copystrcontent=0,
+ strsetitem=4, call=2, newstr=2)
else:
- self.check_loops(newunicode=1, unicodesetitem=2,
- copyunicodecontent=0,
- call=1, call_pure=0) # escape
+ self.check_resops(call_pure=0, unicodesetitem=4, call=2,
+ copyunicodecontent=0, newunicode=2)
def test_strconcat_escape_str_char_str(self):
_str, _chr = self._str, self._chr
@@ -263,12 +259,11 @@
return 42
self.meta_interp(f, [6, 7])
if _str is str:
- self.check_loops(newstr=1, strsetitem=1, copystrcontent=2,
- call=1, call_pure=0) # escape
+ self.check_resops(call_pure=0, copystrcontent=4, strsetitem=2,
+ call=2, newstr=2)
else:
- self.check_loops(newunicode=1, unicodesetitem=1,
- copyunicodecontent=2,
- call=1, call_pure=0) # escape
+ self.check_resops(call_pure=0, unicodesetitem=2, call=2,
+ copyunicodecontent=4, newunicode=2)
def test_strconcat_guard_fail(self):
_str = self._str
@@ -325,7 +320,7 @@
m -= 1
return 42
self.meta_interp(f, [6, 7])
- self.check_loops(newstr=0, newunicode=0)
+ self.check_resops(newunicode=0, newstr=0)
def test_str_slice_len_surviving(self):
_str = self._str
@@ -491,7 +486,7 @@
def __init__(self, s):
self.defaultencoding = s
_str = self._str
- sys = Sys(_str('ascii'))
+ sys = Sys(_str('ascii'))
mydriver = JitDriver(reds = ['n', 'sa'], greens = [])
def f(n):
sa = 0
@@ -504,13 +499,13 @@
sys.defaultencoding = _str('utf-8')
return sa
assert self.meta_interp(f, [8]) == f(8)
- self.check_loops({'int_add': 1, 'guard_true': 1, 'int_sub': 1,
- 'jump': 1, 'int_is_true': 1,
- 'guard_not_invalidated': 1})
+ self.check_resops({'jump': 2, 'int_is_true': 2, 'int_add': 2,
+ 'guard_true': 2, 'guard_not_invalidated': 2,
+ 'int_sub': 2})
def test_promote_string(self):
driver = JitDriver(greens = [], reds = ['n'])
-
+
def f(n):
while n < 21:
driver.jit_merge_point(n=n)
@@ -519,7 +514,7 @@
return 0
self.meta_interp(f, [0])
- self.check_loops(call=3 + 1) # one for int2str
+ self.check_resops(call=7)
#class TestOOtype(StringTests, OOJitMixin):
# CALL = "oosend"
@@ -552,9 +547,8 @@
m -= 1
return 42
self.meta_interp(f, [6, 7])
- self.check_loops(call=1, # escape()
- newunicode=1, unicodegetitem=0,
- unicodesetitem=1, copyunicodecontent=1)
+ self.check_resops(unicodesetitem=2, newunicode=2, call=4,
+ copyunicodecontent=2, unicodegetitem=0)
def test_str2unicode_fold(self):
_str = self._str
@@ -572,9 +566,9 @@
m -= 1
return 42
self.meta_interp(f, [6, 7])
- self.check_loops(call_pure=0, call=1,
- newunicode=0, unicodegetitem=0,
- unicodesetitem=0, copyunicodecontent=0)
+ self.check_resops(call_pure=0, unicodesetitem=0, call=2,
+ newunicode=0, unicodegetitem=0,
+ copyunicodecontent=0)
def test_join_chars(self):
jitdriver = JitDriver(reds=['a', 'b', 'c', 'i'], greens=[])
@@ -596,9 +590,8 @@
# The "".join should be unrolled, since the length of x is known since
# it is virtual, ensure there are no calls to ll_join_chars, or
# allocations.
- self.check_loops({
- "guard_true": 5, "int_is_true": 3, "int_lt": 2, "int_add": 2, "jump": 2,
- }, everywhere=True)
+ self.check_resops({'jump': 2, 'guard_true': 5, 'int_lt': 2,
+ 'int_add': 2, 'int_is_true': 3})
def test_virtual_copystringcontent(self):
jitdriver = JitDriver(reds=['n', 'result'], greens=[])
diff --git a/pypy/jit/metainterp/test/test_tl.py b/pypy/jit/metainterp/test/test_tl.py
--- a/pypy/jit/metainterp/test/test_tl.py
+++ b/pypy/jit/metainterp/test/test_tl.py
@@ -72,16 +72,16 @@
res = self.meta_interp(main, [0, 6], listops=True,
backendopt=True)
assert res == 5040
- self.check_loops({'int_mul':1, 'jump':1,
- 'int_sub':1, 'int_le':1, 'guard_false':1})
+ self.check_resops({'jump': 2, 'int_le': 2, 'guard_value': 1,
+ 'int_mul': 2, 'guard_false': 2, 'int_sub': 2})
def test_tl_2(self):
main = self._get_main()
res = self.meta_interp(main, [1, 10], listops=True,
backendopt=True)
assert res == main(1, 10)
- self.check_loops({'int_sub':1, 'int_le':1,
- 'guard_false':1, 'jump':1})
+ self.check_resops({'int_le': 2, 'int_sub': 2, 'jump': 2,
+ 'guard_false': 2, 'guard_value': 1})
def test_tl_call(self, listops=True, policy=None):
from pypy.jit.tl.tl import interp
diff --git a/pypy/jit/metainterp/test/test_tracingopts.py b/pypy/jit/metainterp/test/test_tracingopts.py
--- a/pypy/jit/metainterp/test/test_tracingopts.py
+++ b/pypy/jit/metainterp/test/test_tracingopts.py
@@ -593,6 +593,32 @@
res = self.interp_operations(fn, [sys.maxint])
assert res == 12
+ def test_opaque_list(self):
+ from pypy.rlib.rerased import new_erasing_pair
+ erase, unerase = new_erasing_pair("test_opaque_list")
+ def fn(n, ca, cb):
+ l1 = [n]
+ l2 = [n]
+ a1 = erase(l1)
+ a2 = erase(l1)
+ a = a1
+ if ca:
+ a = a2
+ if n < -100:
+ unerase(a).append(5)
+ b = a1
+ if cb:
+ b = a
+ return unerase(a)[0] + unerase(b)[0]
+ res = self.interp_operations(fn, [7, 0, 1])
+ assert res == 7 * 2
+ self.check_operations_history(getarrayitem_gc=0,
+ getfield_gc=0)
+ res = self.interp_operations(fn, [-7, 1, 1])
+ assert res == -7 * 2
+ self.check_operations_history(getarrayitem_gc=0,
+ getfield_gc=0)
+
def test_copy_str_content(self):
def fn(n):
a = StringBuilder()
@@ -601,4 +627,4 @@
return x[0]
res = self.interp_operations(fn, [0])
assert res == 1
- self.check_operations_history(getarrayitem_gc=0, getarrayitem_gc_pure=0 )
\ No newline at end of file
+ self.check_operations_history(getarrayitem_gc=0, getarrayitem_gc_pure=0)
diff --git a/pypy/jit/metainterp/test/test_virtual.py b/pypy/jit/metainterp/test/test_virtual.py
--- a/pypy/jit/metainterp/test/test_virtual.py
+++ b/pypy/jit/metainterp/test/test_virtual.py
@@ -31,8 +31,9 @@
res = self.meta_interp(f, [10])
assert res == 55 * 10
self.check_loop_count(1)
- self.check_loops(new=0, new_with_vtable=0,
- getfield_gc=0, setfield_gc=0)
+ self.check_resops(new_with_vtable=0, setfield_gc=0,
+ getfield_gc=2, new=0)
+
def test_virtualized2(self):
myjitdriver = JitDriver(greens = [], reds = ['n', 'node1', 'node2'])
@@ -53,8 +54,8 @@
n -= 1
return node1.value * node2.value
assert f(10) == self.meta_interp(f, [10])
- self.check_loops(new=0, new_with_vtable=0,
- getfield_gc=0, setfield_gc=0)
+ self.check_resops(new_with_vtable=0, setfield_gc=0, getfield_gc=2,
+ new=0)
def test_virtualized_circular1(self):
class MyNode():
@@ -79,8 +80,8 @@
res = self.meta_interp(f, [10])
assert res == 55 * 10
self.check_loop_count(1)
- self.check_loops(new=0, new_with_vtable=0,
- getfield_gc=0, setfield_gc=0)
+ self.check_resops(new_with_vtable=0, setfield_gc=0,
+ getfield_gc=3, new=0)
def test_virtualized_float(self):
myjitdriver = JitDriver(greens = [], reds = ['n', 'node'])
@@ -97,7 +98,7 @@
res = self.meta_interp(f, [10])
assert res == f(10)
self.check_loop_count(1)
- self.check_loops(new=0, float_add=0)
+ self.check_resops(new=0, float_add=1)
def test_virtualized_float2(self):
myjitdriver = JitDriver(greens = [], reds = ['n', 'node'])
@@ -115,7 +116,8 @@
res = self.meta_interp(f, [10])
assert res == f(10)
self.check_loop_count(1)
- self.check_loops(new=0, float_add=1)
+ self.check_resops(new=0, float_add=2)
+
def test_virtualized_2(self):
myjitdriver = JitDriver(greens = [], reds = ['n', 'node'])
@@ -139,8 +141,8 @@
res = self.meta_interp(f, [10])
assert res == 55 * 30
self.check_loop_count(1)
- self.check_loops(new=0, new_with_vtable=0,
- getfield_gc=0, setfield_gc=0)
+ self.check_resops(new_with_vtable=0, setfield_gc=0, getfield_gc=2,
+ new=0)
def test_nonvirtual_obj_delays_loop(self):
myjitdriver = JitDriver(greens = [], reds = ['n', 'node'])
@@ -160,8 +162,8 @@
res = self.meta_interp(f, [500])
assert res == 640
self.check_loop_count(1)
- self.check_loops(new=0, new_with_vtable=0,
- getfield_gc=0, setfield_gc=0)
+ self.check_resops(new_with_vtable=0, setfield_gc=0,
+ getfield_gc=1, new=0)
def test_two_loops_with_virtual(self):
myjitdriver = JitDriver(greens = [], reds = ['n', 'node'])
@@ -184,8 +186,9 @@
res = self.meta_interp(f, [18])
assert res == f(18)
self.check_loop_count(2)
- self.check_loops(new=0, new_with_vtable=0,
- getfield_gc=0, setfield_gc=0)
+ self.check_resops(new_with_vtable=0, setfield_gc=0,
+ getfield_gc=2, new=0)
+
def test_two_loops_with_escaping_virtual(self):
myjitdriver = JitDriver(greens = [], reds = ['n', 'node'])
@@ -212,8 +215,8 @@
res = self.meta_interp(f, [20], policy=StopAtXPolicy(externfn))
assert res == f(20)
self.check_loop_count(3)
- self.check_loops(**{self._new_op: 1})
- self.check_loops(int_mul=0, call=1)
+ self.check_resops(**{self._new_op: 1})
+ self.check_resops(int_mul=0, call=1)
def test_two_virtuals(self):
myjitdriver = JitDriver(greens = [], reds = ['n', 'prev'])
@@ -236,7 +239,7 @@
res = self.meta_interp(f, [12])
assert res == 78
- self.check_loops(new_with_vtable=0, new=0)
+ self.check_resops(new_with_vtable=0, new=0)
def test_specialied_bridge(self):
myjitdriver = JitDriver(greens = [], reds = ['y', 'x', 'res'])
@@ -281,7 +284,7 @@
res = self.meta_interp(f, [20])
assert res == 9
- self.check_loops(new_with_vtable=0, new=0)
+ self.check_resops(new_with_vtable=0, new=0)
def test_immutable_constant_getfield(self):
myjitdriver = JitDriver(greens = ['stufflist'], reds = ['n', 'i'])
@@ -307,7 +310,7 @@
res = self.meta_interp(f, [10, 1, 0], listops=True)
assert res == 0
- self.check_loops(getfield_gc=0)
+ self.check_resops(getfield_gc=0)
def test_escapes(self):
myjitdriver = JitDriver(greens = [], reds = ['n', 'parent'])
@@ -336,7 +339,7 @@
res = self.meta_interp(f, [10], policy=StopAtXPolicy(g))
assert res == 3
- self.check_loops(**{self._new_op: 1})
+ self.check_resops(**{self._new_op: 1})
def test_virtual_on_virtual(self):
myjitdriver = JitDriver(greens = [], reds = ['n', 'parent'])
@@ -366,7 +369,7 @@
res = self.meta_interp(f, [10])
assert res == 2
- self.check_loops(new=0, new_with_vtable=0)
+ self.check_resops(new=0, new_with_vtable=0)
def test_bridge_from_interpreter(self):
mydriver = JitDriver(reds = ['n', 'f'], greens = [])
@@ -841,7 +844,7 @@
del t2
return i
assert self.meta_interp(f, []) == 10
- self.check_loops(new_array=0)
+ self.check_resops(new_array=0)
def test_virtual_streq_bug(self):
mydriver = JitDriver(reds = ['i', 's', 'a'], greens = [])
@@ -942,8 +945,8 @@
res = self.meta_interp(f, [16])
assert res == f(16)
- self.check_loops(getfield_gc=2)
-
+ self.check_resops(getfield_gc=7)
+
# ____________________________________________________________
# Run 1: all the tests instantiate a real RPython class
@@ -985,10 +988,8 @@
res = self.meta_interp(f, [10])
assert res == 20
self.check_loop_count(1)
- self.check_loops(new=0, new_with_vtable=0,
- getfield_gc=0, setfield_gc=0)
-
-
+ self.check_resops(new_with_vtable=0, setfield_gc=0, getfield_gc=0,
+ new=0)
class TestOOtype_Instance(VirtualTests, OOJitMixin):
_new_op = 'new_with_vtable'
diff --git a/pypy/jit/metainterp/test/test_virtualizable.py b/pypy/jit/metainterp/test/test_virtualizable.py
--- a/pypy/jit/metainterp/test/test_virtualizable.py
+++ b/pypy/jit/metainterp/test/test_virtualizable.py
@@ -77,7 +77,7 @@
return xy.inst_x
res = self.meta_interp(f, [20])
assert res == 30
- self.check_loops(getfield_gc=0, setfield_gc=0)
+ self.check_resops(setfield_gc=0, getfield_gc=0)
def test_preexisting_access_2(self):
myjitdriver = JitDriver(greens = [], reds = ['n', 'xy'],
@@ -102,7 +102,7 @@
assert f(5) == 185
res = self.meta_interp(f, [5])
assert res == 185
- self.check_loops(getfield_gc=0, setfield_gc=0)
+ self.check_resops(setfield_gc=0, getfield_gc=0)
def test_two_paths_access(self):
myjitdriver = JitDriver(greens = [], reds = ['n', 'xy'],
@@ -124,7 +124,7 @@
return xy.inst_x
res = self.meta_interp(f, [18])
assert res == 10118
- self.check_loops(getfield_gc=0, setfield_gc=0)
+ self.check_resops(setfield_gc=0, getfield_gc=0)
def test_synchronize_in_return(self):
myjitdriver = JitDriver(greens = [], reds = ['n', 'xy'],
@@ -146,7 +146,7 @@
return xy.inst_x
res = self.meta_interp(f, [18])
assert res == 10180
- self.check_loops(getfield_gc=0, setfield_gc=0)
+ self.check_resops(setfield_gc=0, getfield_gc=0)
def test_virtualizable_and_greens(self):
myjitdriver = JitDriver(greens = ['m'], reds = ['n', 'xy'],
@@ -174,7 +174,7 @@
return res
res = self.meta_interp(f, [40])
assert res == 50 * 4
- self.check_loops(getfield_gc=0, setfield_gc=0)
+ self.check_resops(setfield_gc=0, getfield_gc=0)
def test_double_frame(self):
myjitdriver = JitDriver(greens = [], reds = ['n', 'xy', 'other'],
@@ -197,8 +197,7 @@
return xy.inst_x
res = self.meta_interp(f, [20])
assert res == 134
- self.check_loops(getfield_gc=0, setfield_gc=1)
- self.check_loops(getfield_gc=1, setfield_gc=2, everywhere=True)
+ self.check_resops(setfield_gc=2, getfield_gc=1)
# ------------------------------
@@ -248,8 +247,8 @@
return xy2.inst_l1[2]
res = self.meta_interp(f, [16])
assert res == 3001 + 16 * 80
- self.check_loops(getfield_gc=0, setfield_gc=0,
- getarrayitem_gc=0, setarrayitem_gc=0)
+ self.check_resops(setarrayitem_gc=0, setfield_gc=0,
+ getarrayitem_gc=0, getfield_gc=0)
def test_synchronize_arrays_in_return(self):
myjitdriver = JitDriver(greens = [], reds = ['n', 'xy2'],
@@ -279,8 +278,7 @@
assert f(18) == 10360
res = self.meta_interp(f, [18])
assert res == 10360
- self.check_loops(getfield_gc=0, setfield_gc=0,
- getarrayitem_gc=0)
+ self.check_resops(setfield_gc=0, getarrayitem_gc=0, getfield_gc=0)
def test_array_length(self):
myjitdriver = JitDriver(greens = [], reds = ['n', 'xy2'],
@@ -306,8 +304,8 @@
return xy2.inst_l1[1]
res = self.meta_interp(f, [18])
assert res == 2941309 + 18
- self.check_loops(getfield_gc=0, setfield_gc=0,
- getarrayitem_gc=0, arraylen_gc=0)
+ self.check_resops(setfield_gc=0, getarrayitem_gc=0,
+ arraylen_gc=0, getfield_gc=0)
def test_residual_function(self):
myjitdriver = JitDriver(greens = [], reds = ['n', 'xy2'],
@@ -340,8 +338,8 @@
return xy2.inst_l1[1]
res = self.meta_interp(f, [18])
assert res == 2941309 + 18
- self.check_loops(getfield_gc=0, setfield_gc=0,
- getarrayitem_gc=0, arraylen_gc=1, call=1)
+ self.check_resops(call=2, setfield_gc=0, getarrayitem_gc=0,
+ arraylen_gc=2, getfield_gc=0)
def test_double_frame_array(self):
myjitdriver = JitDriver(greens = [], reds = ['n', 'xy2', 'other'],
@@ -377,8 +375,8 @@
expected = f(20)
res = self.meta_interp(f, [20], enable_opts='')
assert res == expected
- self.check_loops(getfield_gc=1, setfield_gc=0,
- arraylen_gc=1, getarrayitem_gc=1, setarrayitem_gc=1)
+ self.check_resops(setarrayitem_gc=1, setfield_gc=0,
+ getarrayitem_gc=1, arraylen_gc=1, getfield_gc=1)
# ------------------------------
@@ -425,8 +423,7 @@
assert f(18) == 10360
res = self.meta_interp(f, [18])
assert res == 10360
- self.check_loops(getfield_gc=0, setfield_gc=0,
- getarrayitem_gc=0)
+ self.check_resops(setfield_gc=0, getarrayitem_gc=0, getfield_gc=0)
# ------------------------------
@@ -460,8 +457,7 @@
res = self.meta_interp(f, [10])
assert res == 55
- self.check_loops(getfield_gc=0, setfield_gc=0)
-
+ self.check_resops(setfield_gc=0, getfield_gc=0)
def test_virtualizable_with_array(self):
myjitdriver = JitDriver(greens = [], reds = ['n', 'x', 'frame'],
@@ -495,8 +491,7 @@
res = self.meta_interp(f, [10, 1], listops=True)
assert res == f(10, 1)
- self.check_loops(getarrayitem_gc=0)
-
+ self.check_resops(getarrayitem_gc=0)
def test_subclass_of_virtualizable(self):
myjitdriver = JitDriver(greens = [], reds = ['frame'],
@@ -524,8 +519,7 @@
res = self.meta_interp(f, [10])
assert res == 55
- self.check_loops(getfield_gc=0, setfield_gc=0)
-
+ self.check_resops(setfield_gc=0, getfield_gc=0)
def test_external_pass(self):
jitdriver = JitDriver(greens = [], reds = ['n', 'z', 'frame'],
@@ -1011,8 +1005,8 @@
res = self.meta_interp(f, [70], listops=True)
assert res == intmask(42 ** 70)
- self.check_loops(int_add=0,
- int_sub=1) # for 'n -= 1' only
+ self.check_resops(int_add=0,
+ int_sub=2) # for 'n -= 1' only
def test_simple_access_directly(self):
myjitdriver = JitDriver(greens = [], reds = ['frame'],
@@ -1043,7 +1037,7 @@
res = self.meta_interp(f, [10])
assert res == 55
- self.check_loops(getfield_gc=0, setfield_gc=0)
+ self.check_resops(setfield_gc=0, getfield_gc=0)
from pypy.jit.backend.test.support import BaseCompiledMixin
if isinstance(self, BaseCompiledMixin):
@@ -1098,42 +1092,42 @@
res = self.meta_interp(f, [10])
assert res == 55
- self.check_loops(new_with_vtable=0)
+ self.check_resops(new_with_vtable=0)
def test_check_for_nonstandardness_only_once(self):
- myjitdriver = JitDriver(greens = [], reds = ['frame'],
- virtualizables = ['frame'])
+ myjitdriver = JitDriver(greens = [], reds = ['frame'],
+ virtualizables = ['frame'])
- class Frame(object):
- _virtualizable2_ = ['x', 'y', 'z']
+ class Frame(object):
+ _virtualizable2_ = ['x', 'y', 'z']
- def __init__(self, x, y, z=1):
- self = hint(self, access_directly=True)
- self.x = x
- self.y = y
- self.z = z
+ def __init__(self, x, y, z=1):
+ self = hint(self, access_directly=True)
+ self.x = x
+ self.y = y
+ self.z = z
- class SomewhereElse:
- pass
- somewhere_else = SomewhereElse()
+ class SomewhereElse:
+ pass
+ somewhere_else = SomewhereElse()
- def f(n):
- frame = Frame(n, 0)
- somewhere_else.top_frame = frame # escapes
- frame = hint(frame, access_directly=True)
- while frame.x > 0:
- myjitdriver.can_enter_jit(frame=frame)
- myjitdriver.jit_merge_point(frame=frame)
- top_frame = somewhere_else.top_frame
- child_frame = Frame(frame.x, top_frame.z, 17)
- frame.y += child_frame.x
- frame.x -= top_frame.z
- return somewhere_else.top_frame.y
-
- res = self.meta_interp(f, [10])
- assert res == 55
- self.check_loops(new_with_vtable=0, ptr_eq=1, everywhere=True)
- self.check_history(ptr_eq=2)
+ def f(n):
+ frame = Frame(n, 0)
+ somewhere_else.top_frame = frame # escapes
+ frame = hint(frame, access_directly=True)
+ while frame.x > 0:
+ myjitdriver.can_enter_jit(frame=frame)
+ myjitdriver.jit_merge_point(frame=frame)
+ top_frame = somewhere_else.top_frame
+ child_frame = Frame(frame.x, top_frame.z, 17)
+ frame.y += child_frame.x
+ frame.x -= top_frame.z
+ return somewhere_else.top_frame.y
+
+ res = self.meta_interp(f, [10])
+ assert res == 55
+ self.check_resops(new_with_vtable=0, ptr_eq=1)
+ self.check_history(ptr_eq=2)
def test_virtual_child_frame_with_arrays(self):
myjitdriver = JitDriver(greens = [], reds = ['frame'],
@@ -1165,7 +1159,7 @@
res = self.meta_interp(f, [10], listops=True)
assert res == 55
- self.check_loops(new_with_vtable=0)
+ self.check_resops(new_with_vtable=0)
def test_blackhole_should_not_pay_attention(self):
myjitdriver = JitDriver(greens = [], reds = ['frame'],
@@ -1203,7 +1197,7 @@
res = self.meta_interp(f, [10])
assert res == 155
- self.check_loops(getfield_gc=0, setfield_gc=0)
+ self.check_resops(setfield_gc=0, getfield_gc=0)
def test_blackhole_should_synchronize(self):
myjitdriver = JitDriver(greens = [], reds = ['frame'],
@@ -1239,7 +1233,7 @@
res = self.meta_interp(f, [10])
assert res == 155
- self.check_loops(getfield_gc=0, setfield_gc=0)
+ self.check_resops(setfield_gc=0, getfield_gc=0)
def test_blackhole_should_not_reenter(self):
if not self.basic:
diff --git a/pypy/jit/metainterp/test/test_virtualref.py b/pypy/jit/metainterp/test/test_virtualref.py
--- a/pypy/jit/metainterp/test/test_virtualref.py
+++ b/pypy/jit/metainterp/test/test_virtualref.py
@@ -171,7 +171,7 @@
return 1
#
self.meta_interp(f, [10])
- self.check_loops(new_with_vtable=1) # the vref
+ self.check_resops(new_with_vtable=2) # the vref
self.check_aborted_count(0)
def test_simple_all_removed(self):
@@ -205,8 +205,7 @@
virtual_ref_finish(vref, xy)
#
self.meta_interp(f, [15])
- self.check_loops(new_with_vtable=0, # all virtualized
- new_array=0)
+ self.check_resops(new_with_vtable=0, new_array=0)
self.check_aborted_count(0)
def test_simple_no_access(self):
@@ -242,7 +241,7 @@
virtual_ref_finish(vref, xy)
#
self.meta_interp(f, [15])
- self.check_loops(new_with_vtable=1, # the vref: xy doesn't need to be forced
+ self.check_resops(new_with_vtable=2, # the vref: xy doesn't need to be forced
new_array=0) # and neither xy.next1/2/3
self.check_aborted_count(0)
@@ -280,8 +279,8 @@
exctx.topframeref = vref_None
#
self.meta_interp(f, [15])
- self.check_loops(new_with_vtable=2, # XY(), the vref
- new_array=3) # next1/2/3
+ self.check_resops(new_with_vtable=4, # XY(), the vref
+ new_array=6) # next1/2/3
self.check_aborted_count(0)
def test_simple_force_sometimes(self):
@@ -320,8 +319,8 @@
#
res = self.meta_interp(f, [30])
assert res == 13
- self.check_loops(new_with_vtable=1, # the vref, but not XY()
- new_array=0) # and neither next1/2/3
+ self.check_resops(new_with_vtable=2, # the vref, but not XY()
+ new_array=0) # and neither next1/2/3
self.check_loop_count(1)
self.check_aborted_count(0)
@@ -362,7 +361,7 @@
#
res = self.meta_interp(f, [30])
assert res == 13
- self.check_loops(new_with_vtable=0, # all virtualized in the n!=13 loop
+ self.check_resops(new_with_vtable=0, # all virtualized in the n!=13 loop
new_array=0)
self.check_loop_count(1)
self.check_aborted_count(0)
@@ -412,7 +411,7 @@
res = self.meta_interp(f, [72])
assert res == 6
self.check_loop_count(2) # the loop and the bridge
- self.check_loops(new_with_vtable=2, # loop: nothing; bridge: vref, xy
+ self.check_resops(new_with_vtable=2, # loop: nothing; bridge: vref, xy
new_array=2) # bridge: next4, next5
self.check_aborted_count(0)
@@ -442,8 +441,8 @@
#
res = self.meta_interp(f, [15])
assert res == 1
- self.check_loops(new_with_vtable=2, # vref, xy
- new_array=1) # next1
+ self.check_resops(new_with_vtable=4, # vref, xy
+ new_array=2) # next1
self.check_aborted_count(0)
def test_recursive_call_1(self):
@@ -543,7 +542,7 @@
#
res = self.meta_interp(f, [15])
assert res == 1
- self.check_loops(new_with_vtable=2) # vref, xy
+ self.check_resops(new_with_vtable=4) # vref, xy
def test_cannot_use_invalid_virtualref(self):
myjitdriver = JitDriver(greens = [], reds = ['n'])
diff --git a/pypy/jit/metainterp/test/test_warmspot.py b/pypy/jit/metainterp/test/test_warmspot.py
--- a/pypy/jit/metainterp/test/test_warmspot.py
+++ b/pypy/jit/metainterp/test/test_warmspot.py
@@ -100,12 +100,12 @@
# check that the set_param will override the default
res = self.meta_interp(f, [10, llstr('')])
assert res == 0
- self.check_loops(new_with_vtable=1)
+ self.check_resops(new_with_vtable=1)
res = self.meta_interp(f, [10, llstr(ALL_OPTS_NAMES)],
enable_opts='')
assert res == 0
- self.check_loops(new_with_vtable=0)
+ self.check_resops(new_with_vtable=0)
def test_unwanted_loops(self):
mydriver = JitDriver(reds = ['n', 'total', 'm'], greens = [])
@@ -160,7 +160,7 @@
return n
self.meta_interp(f, [50], backendopt=True)
self.check_enter_count_at_most(2)
- self.check_loops(call=0)
+ self.check_resops(call=0)
def test_loop_header(self):
# artificial test: we enter into the JIT only when can_enter_jit()
@@ -184,7 +184,7 @@
assert f(15) == 1
res = self.meta_interp(f, [15], backendopt=True)
assert res == 1
- self.check_loops(int_add=1) # I get 13 without the loop_header()
+ self.check_resops(int_add=2) # I get 13 without the loop_header()
def test_omit_can_enter_jit(self):
# Simple test comparing the effects of always giving a can_enter_jit(),
@@ -246,8 +246,8 @@
m = m - 1
self.meta_interp(f1, [8])
self.check_loop_count(1)
- self.check_loops({'int_sub': 1, 'int_gt': 1, 'guard_true': 1,
- 'jump': 1})
+ self.check_resops({'jump': 2, 'guard_true': 2, 'int_gt': 2,
+ 'int_sub': 2})
def test_void_red_variable(self):
mydriver = JitDriver(greens=[], reds=['a', 'm'])
diff --git a/pypy/jit/tl/spli/test/test_jit.py b/pypy/jit/tl/spli/test/test_jit.py
--- a/pypy/jit/tl/spli/test/test_jit.py
+++ b/pypy/jit/tl/spli/test/test_jit.py
@@ -36,7 +36,7 @@
i = i + 1
return i
self.interpret(f, [])
- self.check_loops(new_with_vtable=0)
+ self.check_resops(new_with_vtable=0)
def test_bridge(self):
py.test.skip('We currently cant virtualize across bridges')
@@ -52,7 +52,7 @@
return total
self.interpret(f, [1, 10])
- self.check_loops(new_with_vtable=0)
+ self.check_resops(new_with_vtable=0)
def test_bridge_bad_case(self):
py.test.skip('We currently cant virtualize across bridges')
@@ -67,7 +67,7 @@
return a + b
self.interpret(f, [1, 10])
- self.check_loops(new_with_vtable=1) # XXX should eventually be 0?
+ self.check_resops(new_with_vtable=1) # XXX should eventually be 0?
# I think it should be either 0 or 2, 1 makes little sense
# If the loop after entering goes first time to the bridge, a
# is rewrapped again, without preserving the identity. I'm not
diff --git a/pypy/module/__builtin__/functional.py b/pypy/module/__builtin__/functional.py
--- a/pypy/module/__builtin__/functional.py
+++ b/pypy/module/__builtin__/functional.py
@@ -95,17 +95,17 @@
return space.newlist(res_w)
-def range_withspecialized_implementation(space, start, step, howmany):
+def range_withspecialized_implementation(space, start, step, length):
assert space.config.objspace.std.withrangelist
- from pypy.objspace.std.rangeobject import W_RangeListObject
- return W_RangeListObject(start, step, howmany)
+ from pypy.objspace.std.listobject import make_range_list
+ return make_range_list(space, start, step, length)
bigint_one = rbigint.fromint(1)
def range_with_longs(space, w_start, w_stop, w_step):
start = lo = space.bigint_w(w_start)
- stop = hi = space.bigint_w(w_stop)
+ hi = space.bigint_w(w_stop)
step = st = space.bigint_w(w_step)
if not step.tobool():
diff --git a/pypy/module/_weakref/test/test_weakref.py b/pypy/module/_weakref/test/test_weakref.py
--- a/pypy/module/_weakref/test/test_weakref.py
+++ b/pypy/module/_weakref/test/test_weakref.py
@@ -324,6 +324,7 @@
class A(object): pass
a = A()
assert _weakref.proxy(a) is _weakref.proxy(a)
+ assert _weakref.proxy(a) is _weakref.proxy(a, None)
def test_callable_proxy(self):
import _weakref, gc
diff --git a/pypy/module/cpyext/listobject.py b/pypy/module/cpyext/listobject.py
--- a/pypy/module/cpyext/listobject.py
+++ b/pypy/module/cpyext/listobject.py
@@ -32,7 +32,7 @@
Py_DecRef(space, w_item)
if not isinstance(w_list, W_ListObject):
PyErr_BadInternalCall(space)
- wrappeditems = w_list.wrappeditems
+ wrappeditems = w_list.getitems()
if index < 0 or index >= len(wrappeditems):
raise OperationError(space.w_IndexError, space.wrap(
"list assignment index out of range"))
@@ -47,7 +47,7 @@
IndexError exception."""
if not isinstance(w_list, W_ListObject):
PyErr_BadInternalCall(space)
- wrappeditems = w_list.wrappeditems
+ wrappeditems = w_list.getitems()
if index < 0 or index >= len(wrappeditems):
raise OperationError(space.w_IndexError, space.wrap(
"list index out of range"))
@@ -74,7 +74,7 @@
"""Macro form of PyList_Size() without error checking.
"""
assert isinstance(w_list, W_ListObject)
- return len(w_list.wrappeditems)
+ return len(w_list.getitems())
@cpython_api([PyObject], Py_ssize_t, error=-1)
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
@@ -56,7 +56,7 @@
PySequence_Fast(), o is not NULL, and that i is within bounds.
"""
if isinstance(w_obj, listobject.W_ListObject):
- w_res = w_obj.wrappeditems[index]
+ w_res = w_obj.getitem(index)
else:
assert isinstance(w_obj, tupleobject.W_TupleObject)
w_res = w_obj.wrappeditems[index]
@@ -70,7 +70,7 @@
PySequence_Fast_GET_SIZE() is faster because it can assume o is a list
or tuple."""
if isinstance(w_obj, listobject.W_ListObject):
- return len(w_obj.wrappeditems)
+ return w_obj.length()
assert isinstance(w_obj, tupleobject.W_TupleObject)
return len(w_obj.wrappeditems)
diff --git a/pypy/module/gc/test/test_referents.py b/pypy/module/gc/test/test_referents.py
--- a/pypy/module/gc/test/test_referents.py
+++ b/pypy/module/gc/test/test_referents.py
@@ -7,9 +7,13 @@
from pypy.rlib import rgc
cls._backup = [rgc.get_rpy_roots]
w = cls.space.wrap
+ space = cls.space
class RandomRPythonObject(object):
pass
- cls.ALL_ROOTS = [w(4), w([2, 7]), RandomRPythonObject()]
+ l4 = space.newlist([w(4)])
+ l2 = space.newlist([w(2)])
+ l7 = space.newlist([w(7)])
+ cls.ALL_ROOTS = [l4, space.newlist([l2, l7]), RandomRPythonObject()]
cls.w_ALL_ROOTS = cls.space.newlist(cls.ALL_ROOTS)
rgc.get_rpy_roots = lambda: (
map(rgc._GcRef, cls.ALL_ROOTS) + [rgc.NULL_GCREF]*17)
@@ -41,14 +45,14 @@
if self.runappdirect:
pass # unsure what to test
else:
- assert lst[0] == 4
- assert lst[1] == [2, 7]
+ assert lst[0] == [4]
+ assert lst[1] == [[2], [7]]
assert type(lst[2]) is gc.GcRef
assert len(lst) == 3
def test_get_rpy_referents(self):
import gc
- y = 12345
+ y = [12345]
x = [y]
lst = gc.get_rpy_referents(x)
# After translation, 'lst' should contain the RPython-level list
@@ -88,8 +92,8 @@
def test_get_referents(self):
import gc
- y = 12345
- z = 23456
+ y = [12345]
+ z = [23456]
x = [y, z]
lst = gc.get_referents(x)
assert y in lst and z in lst
diff --git a/pypy/module/micronumpy/__init__.py b/pypy/module/micronumpy/__init__.py
--- a/pypy/module/micronumpy/__init__.py
+++ b/pypy/module/micronumpy/__init__.py
@@ -5,14 +5,16 @@
applevel_name = 'numpypy'
interpleveldefs = {
- 'array': 'interp_numarray.SingleDimArray',
+ 'array': 'interp_numarray.NDimArray',
'dtype': 'interp_dtype.W_Dtype',
'ufunc': 'interp_ufuncs.W_Ufunc',
'zeros': 'interp_numarray.zeros',
'empty': 'interp_numarray.zeros',
'ones': 'interp_numarray.ones',
+ 'dot': 'interp_numarray.dot',
'fromstring': 'interp_support.fromstring',
+ 'flatiter': 'interp_numarray.W_FlatIterator',
'True_': 'space.w_True',
'False_': 'space.w_False',
@@ -48,6 +50,7 @@
("sign", "sign"),
("sin", "sin"),
("subtract", "subtract"),
+ ('sqrt', 'sqrt'),
("tan", "tan"),
]:
interpleveldefs[exposed] = "interp_ufuncs.get(space).%s" % impl
@@ -57,4 +60,5 @@
'mean': 'app_numpy.mean',
'inf': 'app_numpy.inf',
'e': 'app_numpy.e',
+ 'arange': 'app_numpy.arange',
}
diff --git a/pypy/module/micronumpy/app_numpy.py b/pypy/module/micronumpy/app_numpy.py
--- a/pypy/module/micronumpy/app_numpy.py
+++ b/pypy/module/micronumpy/app_numpy.py
@@ -6,12 +6,33 @@
inf = float("inf")
e = math.e
+
def average(a):
# This implements a weighted average, for now we don't implement the
# weighting, just the average part!
return mean(a)
+
def mean(a):
if not hasattr(a, "mean"):
a = numpypy.array(a)
return a.mean()
+
+
+def arange(start, stop=None, step=1, dtype=None):
+ '''arange([start], stop[, step], dtype=None)
+ Generate values in the half-interval [start, stop).
+ '''
+ if stop is None:
+ stop = start
+ start = 0
+ if dtype is None:
+ test = numpypy.array([start, stop, step, 0])
+ dtype = test.dtype
+ arr = numpypy.zeros(int(math.ceil((stop - start) / step)), dtype=dtype)
+ i = start
+ for j in range(arr.size):
+ arr[j] = i
+ j += 1
+ i += step
+ return arr
diff --git a/pypy/module/micronumpy/compile.py b/pypy/module/micronumpy/compile.py
--- a/pypy/module/micronumpy/compile.py
+++ b/pypy/module/micronumpy/compile.py
@@ -6,10 +6,10 @@
from pypy.interpreter.baseobjspace import InternalSpaceCache, W_Root
from pypy.module.micronumpy.interp_dtype import W_Float64Dtype, W_BoolDtype
from pypy.module.micronumpy.interp_numarray import (Scalar, BaseArray,
- descr_new_array, scalar_w, SingleDimArray)
+ descr_new_array, scalar_w, NDimArray)
from pypy.module.micronumpy import interp_ufuncs
from pypy.rlib.objectmodel import specialize
-
+import re
class BogusBytecode(Exception):
pass
@@ -23,11 +23,18 @@
class WrongFunctionName(Exception):
pass
+class TokenizerError(Exception):
+ pass
+
+class BadToken(Exception):
+ pass
+
SINGLE_ARG_FUNCTIONS = ["sum", "prod", "max", "min", "all", "any", "unegative"]
class FakeSpace(object):
w_ValueError = None
w_TypeError = None
+ w_IndexError = None
w_None = None
w_bool = "bool"
@@ -36,6 +43,7 @@
w_list = "list"
w_long = "long"
w_tuple = 'tuple'
+ w_slice = "slice"
def __init__(self):
"""NOT_RPYTHON"""
@@ -43,13 +51,26 @@
self.w_float64dtype = W_Float64Dtype(self)
def issequence_w(self, w_obj):
- return isinstance(w_obj, ListObject) or isinstance(w_obj, SingleDimArray)
+ return isinstance(w_obj, ListObject) or isinstance(w_obj, NDimArray)
def isinstance_w(self, w_obj, w_tp):
+ if w_obj.tp == w_tp:
+ return True
return False
def decode_index4(self, w_idx, size):
- return (self.int_w(w_idx), 0, 0, 1)
+ if isinstance(w_idx, IntObject):
+ return (self.int_w(w_idx), 0, 0, 1)
+ else:
+ assert isinstance(w_idx, SliceObject)
+ start, stop, step = w_idx.start, w_idx.stop, w_idx.step
+ if step == 0:
+ return (0, size, 1, size)
+ if start < 0:
+ start += size
+ if stop < 0:
+ stop += size
+ return (start, stop, step, size//step)
@specialize.argtype(1)
def wrap(self, obj):
@@ -59,7 +80,9 @@
return BoolObject(obj)
elif isinstance(obj, int):
return IntObject(obj)
- raise Exception
+ elif isinstance(obj, W_Root):
+ return obj
+ raise NotImplementedError
def newlist(self, items):
return ListObject(items)
@@ -67,6 +90,7 @@
def listview(self, obj):
assert isinstance(obj, ListObject)
return obj.items
+ fixedview = listview
def float(self, w_obj):
assert isinstance(w_obj, FloatObject)
@@ -107,6 +131,12 @@
assert isinstance(what, tp)
return what
+ def len_w(self, w_obj):
+ if isinstance(w_obj, ListObject):
+ return len(w_obj.items)
+ # XXX array probably
+ assert False
+
class FloatObject(W_Root):
tp = FakeSpace.w_float
def __init__(self, floatval):
@@ -127,6 +157,13 @@
def __init__(self, items):
self.items = items
+class SliceObject(W_Root):
+ tp = FakeSpace.w_slice
+ def __init__(self, start, stop, step):
+ self.start = start
+ self.stop = stop
+ self.step = step
+
class InterpreterState(object):
def __init__(self, code):
self.code = code
@@ -161,7 +198,7 @@
interp.variables[self.name] = self.expr.execute(interp)
def __repr__(self):
- return "%% = %r" % (self.name, self.expr)
+ return "%r = %r" % (self.name, self.expr)
class ArrayAssignment(Node):
def __init__(self, name, index, expr):
@@ -171,8 +208,11 @@
def execute(self, interp):
arr = interp.variables[self.name]
- w_index = self.index.execute(interp).eval(0).wrap(interp.space)
- w_val = self.expr.execute(interp).eval(0).wrap(interp.space)
+ w_index = self.index.execute(interp).eval(arr.start_iter()).wrap(interp.space)
+ # cast to int
+ if isinstance(w_index, FloatObject):
+ w_index = IntObject(int(w_index.floatval))
+ w_val = self.expr.execute(interp).eval(arr.start_iter()).wrap(interp.space)
arr.descr_setitem(interp.space, w_index, w_val)
def __repr__(self):
@@ -180,7 +220,7 @@
class Variable(Node):
def __init__(self, name):
- self.name = name
+ self.name = name.strip(" ")
def execute(self, interp):
return interp.variables[self.name]
@@ -196,11 +236,11 @@
def execute(self, interp):
w_lhs = self.lhs.execute(interp)
+ if isinstance(self.rhs, SliceConstant):
+ w_rhs = self.rhs.wrap(interp.space)
+ else:
+ w_rhs = self.rhs.execute(interp)
assert isinstance(w_lhs, BaseArray)
- if isinstance(self.rhs, SliceConstant):
- # XXX interface has changed on multidim branch
- raise NotImplementedError
- w_rhs = self.rhs.execute(interp)
if self.name == '+':
w_res = w_lhs.descr_add(interp.space, w_rhs)
elif self.name == '*':
@@ -209,12 +249,10 @@
w_res = w_lhs.descr_sub(interp.space, w_rhs)
elif self.name == '->':
if isinstance(w_rhs, Scalar):
- index = int(interp.space.float_w(
- w_rhs.value.wrap(interp.space)))
- dtype = interp.space.fromcache(W_Float64Dtype)
- return Scalar(dtype, w_lhs.get_concrete().eval(index))
- else:
- raise NotImplementedError
+ w_rhs = w_rhs.eval(w_rhs.start_iter()).wrap(interp.space)
+ assert isinstance(w_rhs, FloatObject)
+ w_rhs = IntObject(int(w_rhs.floatval))
+ w_res = w_lhs.descr_getitem(interp.space, w_rhs)
else:
raise NotImplementedError
if not isinstance(w_res, BaseArray):
@@ -248,7 +286,8 @@
w_list = interp.space.newlist(
[interp.space.wrap(float(i)) for i in range(self.v)])
dtype = interp.space.fromcache(W_Float64Dtype)
- return descr_new_array(interp.space, None, w_list, w_dtype=dtype)
+ return descr_new_array(interp.space, None, w_list, w_dtype=dtype,
+ w_order=None)
def __repr__(self):
return 'Range(%s)' % self.v
@@ -270,17 +309,24 @@
def execute(self, interp):
w_list = self.wrap(interp.space)
dtype = interp.space.fromcache(W_Float64Dtype)
- return descr_new_array(interp.space, None, w_list, w_dtype=dtype)
+ return descr_new_array(interp.space, None, w_list, w_dtype=dtype,
+ w_order=None)
def __repr__(self):
return "[" + ", ".join([repr(item) for item in self.items]) + "]"
class SliceConstant(Node):
- def __init__(self):
- pass
+ def __init__(self, start, stop, step):
+ # no negative support for now
+ self.start = start
+ self.stop = stop
+ self.step = step
+
+ def wrap(self, space):
+ return SliceObject(self.start, self.stop, self.step)
def __repr__(self):
- return 'slice()'
+ return 'slice(%s,%s,%s)' % (self.start, self.stop, self.step)
class Execute(Node):
def __init__(self, expr):
@@ -294,7 +340,7 @@
class FunctionCall(Node):
def __init__(self, name, args):
- self.name = name
+ self.name = name.strip(" ")
self.args = args
def __repr__(self):
@@ -337,95 +383,172 @@
else:
raise WrongFunctionName
+_REGEXES = [
+ ('-?[\d\.]+', 'number'),
+ ('\[', 'array_left'),
+ (':', 'colon'),
+ ('\w+', 'identifier'),
+ ('\]', 'array_right'),
+ ('(->)|[\+\-\*\/]', 'operator'),
+ ('=', 'assign'),
+ (',', 'coma'),
+ ('\|', 'pipe'),
+ ('\(', 'paren_left'),
+ ('\)', 'paren_right'),
+]
+REGEXES = []
+
+for r, name in _REGEXES:
+ REGEXES.append((re.compile(r' *(' + r + ')'), name))
+del _REGEXES
+
+class Token(object):
+ def __init__(self, name, v):
+ self.name = name
+ self.v = v
+
+ def __repr__(self):
+ return '(%s, %s)' % (self.name, self.v)
+
+empty = Token('', '')
+
+class TokenStack(object):
+ def __init__(self, tokens):
+ self.tokens = tokens
+ self.c = 0
+
+ def pop(self):
+ token = self.tokens[self.c]
+ self.c += 1
+ return token
+
+ def get(self, i):
+ if self.c + i >= len(self.tokens):
+ return empty
+ return self.tokens[self.c + i]
+
+ def remaining(self):
+ return len(self.tokens) - self.c
+
+ def push(self):
+ self.c -= 1
+
+ def __repr__(self):
+ return repr(self.tokens[self.c:])
+
class Parser(object):
- def parse_identifier(self, id):
- id = id.strip(" ")
- #assert id.isalpha()
- return Variable(id)
+ def tokenize(self, line):
+ tokens = []
+ while True:
+ for r, name in REGEXES:
+ m = r.match(line)
+ if m is not None:
+ g = m.group(0)
+ tokens.append(Token(name, g))
+ line = line[len(g):]
+ if not line:
+ return TokenStack(tokens)
+ break
+ else:
+ raise TokenizerError(line)
- def parse_expression(self, expr):
- tokens = [i for i in expr.split(" ") if i]
- if len(tokens) == 1:
- return self.parse_constant_or_identifier(tokens[0])
+ def parse_number_or_slice(self, tokens):
+ start_tok = tokens.pop()
+ if start_tok.name == 'colon':
+ start = 0
+ else:
+ if tokens.get(0).name != 'colon':
+ return FloatConstant(start_tok.v)
+ start = int(start_tok.v)
+ tokens.pop()
+ if not tokens.get(0).name in ['colon', 'number']:
+ stop = -1
+ step = 1
+ else:
+ next = tokens.pop()
+ if next.name == 'colon':
+ stop = -1
+ step = int(tokens.pop().v)
+ else:
+ stop = int(next.v)
+ if tokens.get(0).name == 'colon':
+ tokens.pop()
+ step = int(tokens.pop().v)
+ else:
+ step = 1
+ return SliceConstant(start, stop, step)
+
+
+ def parse_expression(self, tokens):
stack = []
- tokens.reverse()
- while tokens:
+ while tokens.remaining():
token = tokens.pop()
- if token == ')':
- raise NotImplementedError
- elif self.is_identifier_or_const(token):
- if stack:
- name = stack.pop().name
- lhs = stack.pop()
- rhs = self.parse_constant_or_identifier(token)
- stack.append(Operator(lhs, name, rhs))
+ if token.name == 'identifier':
+ if tokens.remaining() and tokens.get(0).name == 'paren_left':
+ stack.append(self.parse_function_call(token.v, tokens))
else:
- stack.append(self.parse_constant_or_identifier(token))
+ stack.append(Variable(token.v))
+ elif token.name == 'array_left':
+ stack.append(ArrayConstant(self.parse_array_const(tokens)))
+ elif token.name == 'operator':
+ stack.append(Variable(token.v))
+ elif token.name == 'number' or token.name == 'colon':
+ tokens.push()
+ stack.append(self.parse_number_or_slice(tokens))
+ elif token.name == 'pipe':
+ stack.append(RangeConstant(tokens.pop().v))
+ end = tokens.pop()
+ assert end.name == 'pipe'
else:
- stack.append(Variable(token))
- assert len(stack) == 1
- return stack[-1]
+ tokens.push()
+ break
+ stack.reverse()
+ lhs = stack.pop()
+ while stack:
+ op = stack.pop()
+ assert isinstance(op, Variable)
+ rhs = stack.pop()
+ lhs = Operator(lhs, op.name, rhs)
+ return lhs
- def parse_constant(self, v):
- lgt = len(v)-1
- assert lgt >= 0
- if ':' in v:
- # a slice
- assert v == ':'
- return SliceConstant()
- if v[0] == '[':
- return ArrayConstant([self.parse_constant(elem)
- for elem in v[1:lgt].split(",")])
- if v[0] == '|':
- return RangeConstant(v[1:lgt])
- return FloatConstant(v)
-
- def is_identifier_or_const(self, v):
- c = v[0]
- if ((c >= 'a' and c <= 'z') or (c >= 'A' and c <= 'Z') or
- (c >= '0' and c <= '9') or c in '-.[|:'):
- if v == '-' or v == "->":
- return False
- return True
- return False
-
- def parse_function_call(self, v):
- l = v.split('(')
- assert len(l) == 2
- name = l[0]
- cut = len(l[1]) - 1
- assert cut >= 0
- args = [self.parse_constant_or_identifier(id)
- for id in l[1][:cut].split(",")]
+ def parse_function_call(self, name, tokens):
+ args = []
+ tokens.pop() # lparen
+ while tokens.get(0).name != 'paren_right':
+ args.append(self.parse_expression(tokens))
return FunctionCall(name, args)
- def parse_constant_or_identifier(self, v):
- c = v[0]
- if (c >= 'a' and c <= 'z') or (c >= 'A' and c <= 'Z'):
- if '(' in v:
- return self.parse_function_call(v)
- return self.parse_identifier(v)
- return self.parse_constant(v)
-
- def parse_array_subscript(self, v):
- v = v.strip(" ")
- l = v.split("[")
- lgt = len(l[1]) - 1
- assert lgt >= 0
- rhs = self.parse_constant_or_identifier(l[1][:lgt])
- return l[0], rhs
+ def parse_array_const(self, tokens):
+ elems = []
+ while True:
+ token = tokens.pop()
+ if token.name == 'number':
+ elems.append(FloatConstant(token.v))
+ elif token.name == 'array_left':
+ elems.append(ArrayConstant(self.parse_array_const(tokens)))
+ else:
+ raise BadToken()
+ token = tokens.pop()
+ if token.name == 'array_right':
+ return elems
+ assert token.name == 'coma'
- def parse_statement(self, line):
- if '=' in line:
- lhs, rhs = line.split("=")
- lhs = lhs.strip(" ")
- if '[' in lhs:
- name, index = self.parse_array_subscript(lhs)
- return ArrayAssignment(name, index, self.parse_expression(rhs))
- else:
- return Assignment(lhs, self.parse_expression(rhs))
- else:
- return Execute(self.parse_expression(line))
+ def parse_statement(self, tokens):
+ if (tokens.get(0).name == 'identifier' and
+ tokens.get(1).name == 'assign'):
+ lhs = tokens.pop().v
+ tokens.pop()
+ rhs = self.parse_expression(tokens)
+ return Assignment(lhs, rhs)
+ elif (tokens.get(0).name == 'identifier' and
+ tokens.get(1).name == 'array_left'):
+ name = tokens.pop().v
+ tokens.pop()
+ index = self.parse_expression(tokens)
+ tokens.pop()
+ tokens.pop()
+ return ArrayAssignment(name, index, self.parse_expression(tokens))
+ return Execute(self.parse_expression(tokens))
def parse(self, code):
statements = []
@@ -434,7 +557,8 @@
line = line.split('#', 1)[0]
line = line.strip(" ")
if line:
- statements.append(self.parse_statement(line))
+ tokens = self.tokenize(line)
+ statements.append(self.parse_statement(tokens))
return Code(statements)
def numpy_compile(code):
diff --git a/pypy/module/micronumpy/interp_dtype.py b/pypy/module/micronumpy/interp_dtype.py
--- a/pypy/module/micronumpy/interp_dtype.py
+++ b/pypy/module/micronumpy/interp_dtype.py
@@ -221,6 +221,7 @@
@binop
def div(self, v1, v2):
+ # XXX this won't work after translation, probably requires ovfcheck
try:
return v1 / v2
except ZeroDivisionError:
@@ -292,6 +293,12 @@
if not -1.0 < v < 1.0:
return rfloat.NAN
return math.atanh(v)
+ @unaryop
+ def sqrt(self, v):
+ try:
+ return math.sqrt(v)
+ except ValueError:
+ return rfloat.NAN
class IntegerArithmeticDtype(ArithmeticTypeMixin):
_mixin_ = True
diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py
--- a/pypy/module/micronumpy/interp_numarray.py
+++ b/pypy/module/micronumpy/interp_numarray.py
@@ -1,45 +1,369 @@
from pypy.interpreter.baseobjspace import Wrappable
-from pypy.interpreter.error import OperationError
-from pypy.interpreter.gateway import interp2app, unwrap_spec
+from pypy.interpreter.error import OperationError, operationerrfmt
+from pypy.interpreter.gateway import interp2app, unwrap_spec, NoneNotWrapped
from pypy.interpreter.typedef import TypeDef, GetSetProperty
from pypy.module.micronumpy import interp_ufuncs, interp_dtype, signature
from pypy.rlib import jit
-from pypy.rpython.lltypesystem import lltype
+from pypy.rpython.lltypesystem import lltype, rffi
from pypy.tool.sourcetools import func_with_new_name
+from pypy.rlib.rstring import StringBuilder
+from pypy.rlib.objectmodel import instantiate
-numpy_driver = jit.JitDriver(greens = ['signature'],
- reds = ['result_size', 'i', 'self', 'result'])
-all_driver = jit.JitDriver(greens=['signature'], reds=['i', 'size', 'self', 'dtype'])
-any_driver = jit.JitDriver(greens=['signature'], reds=['i', 'size', 'self', 'dtype'])
-slice_driver = jit.JitDriver(greens=['signature'], reds=['i', 'j', 'step', 'stop', 'source', 'dest'])
+numpy_driver = jit.JitDriver(
+ greens=['shapelen', 'signature'],
+ reds=['result_size', 'i', 'ri', 'self', 'result']
+)
+all_driver = jit.JitDriver(
+ greens=['shapelen', 'signature'],
+ reds=['i', 'self', 'dtype']
+)
+any_driver = jit.JitDriver(
+ greens=['shapelen', 'signature'],
+ reds=['i', 'self', 'dtype']
+)
+slice_driver = jit.JitDriver(
+ greens=['shapelen', 'signature'],
+ reds=['self', 'source', 'source_iter', 'res_iter']
+)
-def descr_new_array(space, w_subtype, w_size_or_iterable, w_dtype=None):
- l = space.listview(w_size_or_iterable)
+def _find_shape_and_elems(space, w_iterable):
+ shape = [space.len_w(w_iterable)]
+ batch = space.listview(w_iterable)
+ while True:
+ new_batch = []
+ if not batch:
+ return shape, []
+ if not space.issequence_w(batch[0]):
+ for elem in batch:
+ if space.issequence_w(elem):
+ raise OperationError(space.w_ValueError, space.wrap(
+ "setting an array element with a sequence"))
+ return shape, batch
+ size = space.len_w(batch[0])
+ for w_elem in batch:
+ if not space.issequence_w(w_elem) or space.len_w(w_elem) != size:
+ raise OperationError(space.w_ValueError, space.wrap(
+ "setting an array element with a sequence"))
+ new_batch += space.listview(w_elem)
+ shape.append(size)
+ batch = new_batch
+
+def shape_agreement(space, shape1, shape2):
+ ret = _shape_agreement(shape1, shape2)
+ if len(ret) < max(len(shape1), len(shape2)):
+ raise OperationError(space.w_ValueError,
+ space.wrap("operands could not be broadcast together with shapes (%s) (%s)" % (
+ ",".join([str(x) for x in shape1]),
+ ",".join([str(x) for x in shape2]),
+ ))
+ )
+ return ret
+
+def _shape_agreement(shape1, shape2):
+ """ Checks agreement about two shapes with respect to broadcasting. Returns
+ the resulting shape.
+ """
+ lshift = 0
+ rshift = 0
+ if len(shape1) > len(shape2):
+ m = len(shape1)
+ n = len(shape2)
+ rshift = len(shape2) - len(shape1)
+ remainder = shape1
+ else:
+ m = len(shape2)
+ n = len(shape1)
+ lshift = len(shape1) - len(shape2)
+ remainder = shape2
+ endshape = [0] * m
+ indices1 = [True] * m
+ indices2 = [True] * m
+ for i in range(m - 1, m - n - 1, -1):
+ left = shape1[i + lshift]
+ right = shape2[i + rshift]
+ if left == right:
+ endshape[i] = left
+ elif left == 1:
+ endshape[i] = right
+ indices1[i + lshift] = False
+ elif right == 1:
+ endshape[i] = left
+ indices2[i + rshift] = False
+ else:
+ return []
+ #raise OperationError(space.w_ValueError, space.wrap(
+ # "frames are not aligned"))
+ for i in range(m - n):
+ endshape[i] = remainder[i]
+ return endshape
+
+def descr_new_array(space, w_subtype, w_item_or_iterable, w_dtype=None,
+ w_order=NoneNotWrapped):
+ # find scalar
+ if not space.issequence_w(w_item_or_iterable):
+ w_dtype = interp_ufuncs.find_dtype_for_scalar(space,
+ w_item_or_iterable,
+ w_dtype)
+ dtype = space.interp_w(interp_dtype.W_Dtype,
+ space.call_function(space.gettypefor(interp_dtype.W_Dtype), w_dtype))
+ return scalar_w(space, dtype, w_item_or_iterable)
+ if w_order is None:
+ order = 'C'
+ else:
+ order = space.str_w(w_order)
+ if order != 'C': # or order != 'F':
+ raise operationerrfmt(space.w_ValueError, "Unknown order: %s",
+ order)
+ shape, elems_w = _find_shape_and_elems(space, w_item_or_iterable)
+ # they come back in C order
+ size = len(elems_w)
if space.is_w(w_dtype, space.w_None):
w_dtype = None
- for w_item in l:
- w_dtype = interp_ufuncs.find_dtype_for_scalar(space, w_item, w_dtype)
+ for w_elem in elems_w:
+ w_dtype = interp_ufuncs.find_dtype_for_scalar(space, w_elem,
+ w_dtype)
if w_dtype is space.fromcache(interp_dtype.W_Float64Dtype):
break
- if w_dtype is None:
- w_dtype = space.w_None
-
+ if w_dtype is None:
+ w_dtype = space.w_None
dtype = space.interp_w(interp_dtype.W_Dtype,
space.call_function(space.gettypefor(interp_dtype.W_Dtype), w_dtype)
)
- arr = SingleDimArray(len(l), dtype=dtype)
- i = 0
- for w_elem in l:
- dtype.setitem_w(space, arr.storage, i, w_elem)
- i += 1
+ arr = NDimArray(size, shape[:], dtype=dtype, order=order)
+ shapelen = len(shape)
+ arr_iter = arr.start_iter(arr.shape)
+ for i in range(len(elems_w)):
+ w_elem = elems_w[i]
+ dtype.setitem_w(space, arr.storage, arr_iter.offset, w_elem)
+ arr_iter = arr_iter.next(shapelen)
return arr
+# Iterators for arrays
+# --------------------
+# all those iterators with the exception of BroadcastIterator iterate over the
+# entire array in C order (the last index changes the fastest). This will
+# yield all elements. Views iterate over indices and look towards strides and
+# backstrides to find the correct position. Notably the offset between
+# x[..., i + 1] and x[..., i] will be strides[-1]. Offset between
+# x[..., k + 1, 0] and x[..., k, i_max] will be backstrides[-2] etc.
+
+# BroadcastIterator works like that, but for indexes that don't change source
+# in the original array, strides[i] == backstrides[i] == 0
+
+class BaseIterator(object):
+ def next(self, shapelen):
+ raise NotImplementedError
+
+ def done(self):
+ raise NotImplementedError
+
+ def get_offset(self):
+ raise NotImplementedError
+
+class ArrayIterator(BaseIterator):
+ def __init__(self, size):
+ self.offset = 0
+ self.size = size
+
+ def next(self, shapelen):
+ arr = instantiate(ArrayIterator)
+ arr.size = self.size
+ arr.offset = self.offset + 1
+ return arr
+
+ def done(self):
+ return self.offset >= self.size
+
+ def get_offset(self):
+ return self.offset
+
+class OneDimIterator(BaseIterator):
+ def __init__(self, start, step, size):
+ self.offset = start
+ self.step = step
+ self.size = size
+
+ def next(self, shapelen):
+ arr = instantiate(OneDimIterator)
+ arr.size = self.size
+ arr.step = self.step
+ arr.offset = self.offset + self.step
+ return arr
+
+ def done(self):
+ return self.offset >= self.size
+
+ def get_offset(self):
+ return self.offset
+
+class ViewIterator(BaseIterator):
+ def __init__(self, arr):
+ self.indices = [0] * len(arr.shape)
+ self.offset = arr.start
+ self.arr = arr
+ self._done = False
+
+ @jit.unroll_safe
+ def next(self, shapelen):
+ offset = self.offset
+ indices = [0] * shapelen
+ for i in range(shapelen):
+ indices[i] = self.indices[i]
+ done = False
+ for i in range(shapelen - 1, -1, -1):
+ if indices[i] < self.arr.shape[i] - 1:
+ indices[i] += 1
+ offset += self.arr.strides[i]
+ break
+ else:
+ indices[i] = 0
+ offset -= self.arr.backstrides[i]
+ else:
+ done = True
+ res = instantiate(ViewIterator)
+ res.offset = offset
+ res.indices = indices
+ res.arr = self.arr
+ res._done = done
+ return res
+
+ def done(self):
+ return self._done
+
+ def get_offset(self):
+ return self.offset
+
+class BroadcastIterator(BaseIterator):
+ '''Like a view iterator, but will repeatedly access values
+ for all iterations across a res_shape, folding the offset
+ using mod() arithmetic
+ '''
+ def __init__(self, arr, res_shape):
+ self.indices = [0] * len(res_shape)
+ self.offset = arr.start
+ #strides are 0 where original shape==1
+ self.strides = []
+ self.backstrides = []
+ for i in range(len(arr.shape)):
+ if arr.shape[i] == 1:
+ self.strides.append(0)
+ self.backstrides.append(0)
+ else:
+ self.strides.append(arr.strides[i])
+ self.backstrides.append(arr.backstrides[i])
+ self.res_shape = res_shape
+ self.strides = [0] * (len(res_shape) - len(arr.shape)) + self.strides
+ self.backstrides = [0] * (len(res_shape) - len(arr.shape)) + self.backstrides
+ self._done = False
+
+ @jit.unroll_safe
+ def next(self, shapelen):
+ offset = self.offset
+ indices = [0] * shapelen
+ _done = False
+ for i in range(shapelen):
+ indices[i] = self.indices[i]
+ for i in range(shapelen - 1, -1, -1):
+ if indices[i] < self.res_shape[i] - 1:
+ indices[i] += 1
+ offset += self.strides[i]
+ break
+ else:
+ indices[i] = 0
+ offset -= self.backstrides[i]
+ else:
+ _done = True
+ res = instantiate(BroadcastIterator)
+ res.indices = indices
+ res.offset = offset
+ res._done = _done
+ res.strides = self.strides
+ res.backstrides = self.backstrides
+ res.res_shape = self.res_shape
+ return res
+
+ def done(self):
+ return self._done
+
+ def get_offset(self):
+ return self.offset
+
+class Call2Iterator(BaseIterator):
+ def __init__(self, left, right):
+ self.left = left
+ self.right = right
+
+ def next(self, shapelen):
+ return Call2Iterator(self.left.next(shapelen),
+ self.right.next(shapelen))
+
+ def done(self):
+ if isinstance(self.left, ConstantIterator):
+ return self.right.done()
+ return self.left.done()
+
+ def get_offset(self):
+ if isinstance(self.left, ConstantIterator):
+ return self.right.get_offset()
+ return self.left.get_offset()
+
+class Call1Iterator(BaseIterator):
+ def __init__(self, child):
+ self.child = child
+
+ def next(self, shapelen):
+ return Call1Iterator(self.child.next(shapelen))
+
+ def done(self):
+ return self.child.done()
+
+ def get_offset(self):
+ return self.child.get_offset()
+
+class ConstantIterator(BaseIterator):
+ def next(self, shapelen):
+ return self
+
+ def done(self):
+ return False
+
+ def get_offset(self):
+ return 0
+
+
class BaseArray(Wrappable):
- _attrs_ = ["invalidates", "signature"]
+ _attrs_ = ["invalidates", "signature", "shape", "strides", "backstrides",
+ "start", 'order']
- def __init__(self):
+ _immutable_fields_ = ['start', "order"]
+
+ strides = None
+ start = 0
+
+ def __init__(self, shape, order):
self.invalidates = []
+ self.shape = shape
+ self.order = order
+ if self.strides is None:
+ self.calc_strides(shape)
+
+ def calc_strides(self, shape):
+ strides = []
+ backstrides = []
+ s = 1
+ shape_rev = shape[:]
+ if self.order == 'C':
+ shape_rev.reverse()
+ for sh in shape_rev:
+ strides.append(s)
+ backstrides.append(s * (sh - 1))
+ s *= sh
+ if self.order == 'C':
+ strides.reverse()
+ backstrides.reverse()
+ self.strides = strides[:]
+ self.backstrides = backstrides[:]
def invalidated(self):
if self.invalidates:
@@ -99,7 +423,7 @@
def _reduce_ufunc_impl(ufunc_name):
def impl(self, space):
- return getattr(interp_ufuncs.get(space), ufunc_name).descr_reduce(space, self)
+ return getattr(interp_ufuncs.get(space), ufunc_name).reduce(space, self, multidim=True)
return func_with_new_name(impl, "reduce_%s_impl" % ufunc_name)
descr_sum = _reduce_ufunc_impl("add")
@@ -108,23 +432,30 @@
descr_min = _reduce_ufunc_impl("minimum")
def _reduce_argmax_argmin_impl(op_name):
- reduce_driver = jit.JitDriver(greens=['signature'],
- reds = ['i', 'size', 'result', 'self', 'cur_best', 'dtype'])
- def loop(self, size):
+ reduce_driver = jit.JitDriver(
+ greens=['shapelen', 'signature'],
+ reds=['result', 'idx', 'i', 'self', 'cur_best', 'dtype']
+ )
+ def loop(self):
+ i = self.start_iter()
+ cur_best = self.eval(i)
+ shapelen = len(self.shape)
+ i = i.next(shapelen)
+ dtype = self.find_dtype()
result = 0
- cur_best = self.eval(0)
- i = 1
- dtype = self.find_dtype()
- while i < size:
+ idx = 1
+ while not i.done():
reduce_driver.jit_merge_point(signature=self.signature,
+ shapelen=shapelen,
self=self, dtype=dtype,
- size=size, i=i, result=result,
+ i=i, result=result, idx=idx,
cur_best=cur_best)
new_best = getattr(dtype, op_name)(cur_best, self.eval(i))
if dtype.ne(new_best, cur_best):
- result = i
+ result = idx
cur_best = new_best
- i += 1
+ i = i.next(shapelen)
+ idx += 1
return result
def impl(self, space):
size = self.find_size()
@@ -132,31 +463,35 @@
raise OperationError(space.w_ValueError,
space.wrap("Can't call %s on zero-size arrays" \
% op_name))
- return space.wrap(loop(self, size))
+ return space.wrap(loop(self))
return func_with_new_name(impl, "reduce_arg%s_impl" % op_name)
def _all(self):
- size = self.find_size()
dtype = self.find_dtype()
- i = 0
- while i < size:
- all_driver.jit_merge_point(signature=self.signature, self=self, dtype=dtype, size=size, i=i)
+ i = self.start_iter()
+ shapelen = len(self.shape)
+ while not i.done():
+ all_driver.jit_merge_point(signature=self.signature,
+ shapelen=shapelen, self=self,
+ dtype=dtype, i=i)
if not dtype.bool(self.eval(i)):
return False
- i += 1
+ i = i.next(shapelen)
return True
def descr_all(self, space):
return space.wrap(self._all())
def _any(self):
- size = self.find_size()
dtype = self.find_dtype()
- i = 0
- while i < size:
- any_driver.jit_merge_point(signature=self.signature, self=self, size=size, dtype=dtype, i=i)
+ i = self.start_iter()
+ shapelen = len(self.shape)
+ while not i.done():
+ any_driver.jit_merge_point(signature=self.signature,
+ shapelen=shapelen, self=self,
+ dtype=dtype, i=i)
if dtype.bool(self.eval(i)):
return True
- i += 1
+ i = i.next(shapelen)
return False
def descr_any(self, space):
return space.wrap(self._any())
@@ -173,25 +508,6 @@
assert isinstance(w_res, BaseArray)
return w_res.descr_sum(space)
- def _getnums(self, comma):
- dtype = self.find_dtype()
- if self.find_size() > 1000:
- nums = [
- dtype.str_format(self.eval(index))
- for index in range(3)
- ]
- nums.append("..." + "," * comma)
- nums.extend([
- dtype.str_format(self.eval(index))
- for index in range(self.find_size() - 3, self.find_size())
- ])
- else:
- nums = [
- dtype.str_format(self.eval(index))
- for index in range(self.find_size())
- ]
- return nums
-
def get_concrete(self):
raise NotImplementedError
@@ -199,101 +515,304 @@
return space.wrap(self.find_dtype())
def descr_get_shape(self, space):
- return space.newtuple([self.descr_len(space)])
+ return space.newtuple([space.wrap(i) for i in self.shape])
def descr_get_size(self, space):
return space.wrap(self.find_size())
def descr_copy(self, space):
- return space.call_function(space.gettypefor(BaseArray), self, self.find_dtype())
+ return self.get_concrete().copy()
def descr_len(self, space):
return self.get_concrete().descr_len(space)
def descr_repr(self, space):
- # Simple implementation so that we can see the array. Needs work.
+ res = StringBuilder()
+ res.append("array(")
concrete = self.get_concrete()
- res = "array([" + ", ".join(concrete._getnums(False)) + "]"
dtype = concrete.find_dtype()
+ if not concrete.find_size():
+ res.append('[]')
+ if len(self.shape) > 1:
+ # An empty slice reports its shape
+ res.append(", shape=(")
+ self_shape = str(self.shape)
+ res.append_slice(str(self_shape), 1, len(self_shape) - 1)
+ res.append(')')
+ else:
+ concrete.to_str(space, 1, res, indent=' ')
if (dtype is not space.fromcache(interp_dtype.W_Float64Dtype) and
- dtype is not space.fromcache(interp_dtype.W_Int64Dtype)) or not self.find_size():
- res += ", dtype=" + dtype.name
- res += ")"
- return space.wrap(res)
+ dtype is not space.fromcache(interp_dtype.W_Int64Dtype)) or \
+ not self.find_size():
+ res.append(", dtype=" + dtype.name)
+ res.append(")")
+ return space.wrap(res.build())
+
+ def to_str(self, space, comma, builder, indent=' ', use_ellipsis=False):
+ '''Modifies builder with a representation of the array/slice
+ The items will be seperated by a comma if comma is 1
+ Multidimensional arrays/slices will span a number of lines,
+ each line will begin with indent.
+ '''
+ size = self.find_size()
+ if size < 1:
+ builder.append('[]')
+ return
+ if size > 1000:
+ # Once this goes True it does not go back to False for recursive
+ # calls
+ use_ellipsis = True
+ dtype = self.find_dtype()
+ ndims = len(self.shape)
+ i = 0
+ start = True
+ builder.append('[')
+ if ndims > 1:
+ if use_ellipsis:
+ for i in range(3):
+ if start:
+ start = False
+ else:
+ builder.append(',' * comma + '\n')
+ if ndims == 3:
+ builder.append('\n' + indent)
+ else:
+ builder.append(indent)
+ # create_slice requires len(chunks) > 1 in order to reduce
+ # shape
+ view = self.create_slice(space, [(i, 0, 0, 1), (0, self.shape[1], 1, self.shape[1])])
+ view.to_str(space, comma, builder, indent=indent + ' ', use_ellipsis=use_ellipsis)
+ builder.append('\n' + indent + '..., ')
+ i = self.shape[0] - 3
+ while i < self.shape[0]:
+ if start:
+ start = False
+ else:
+ builder.append(',' * comma + '\n')
+ if ndims == 3:
+ builder.append('\n' + indent)
+ else:
+ builder.append(indent)
+ # create_slice requires len(chunks) > 1 in order to reduce
+ # shape
+ view = self.create_slice(space, [(i, 0, 0, 1), (0, self.shape[1], 1, self.shape[1])])
+ view.to_str(space, comma, builder, indent=indent + ' ', use_ellipsis=use_ellipsis)
+ i += 1
+ elif ndims == 1:
+ spacer = ',' * comma + ' '
+ item = self.start
+ # An iterator would be a nicer way to walk along the 1d array, but
+ # how do I reset it if printing ellipsis? iterators have no
+ # "set_offset()"
+ i = 0
+ if use_ellipsis:
+ for i in range(3):
+ if start:
+ start = False
+ else:
+ builder.append(spacer)
+ builder.append(dtype.str_format(self.getitem(item)))
+ item += self.strides[0]
+ # Add a comma only if comma is False - this prevents adding two
+ # commas
+ builder.append(spacer + '...' + ',' * (1 - comma))
+ # Ugly, but can this be done with an iterator?
+ item = self.start + self.backstrides[0] - 2 * self.strides[0]
+ i = self.shape[0] - 3
+ while i < self.shape[0]:
+ if start:
+ start = False
+ else:
+ builder.append(spacer)
+ builder.append(dtype.str_format(self.getitem(item)))
+ item += self.strides[0]
+ i += 1
+ else:
+ builder.append('[')
+ builder.append(']')
def descr_str(self, space):
- # Simple implementation so that we can see the array. Needs work.
+ ret = StringBuilder()
concrete = self.get_concrete()
- return space.wrap("[" + " ".join(concrete._getnums(True)) + "]")
+ concrete.to_str(space, 0, ret, ' ')
+ return space.wrap(ret.build())
+
+ @jit.unroll_safe
+ def _index_of_single_item(self, space, w_idx):
+ if space.isinstance_w(w_idx, space.w_int):
+ idx = space.int_w(w_idx)
+ if not self.shape:
+ if idx != 0:
+ raise OperationError(space.w_IndexError,
+ space.wrap("index out of range"))
+ return 0
+ if idx < 0:
+ idx = self.shape[0] + idx
+ if idx < 0 or idx >= self.shape[0]:
+ raise OperationError(space.w_IndexError,
+ space.wrap("index out of range"))
+ return self.start + idx * self.strides[0]
+ index = [space.int_w(w_item)
+ for w_item in space.fixedview(w_idx)]
+ item = self.start
+ for i in range(len(index)):
+ v = index[i]
+ if v < 0:
+ v += self.shape[i]
+ if v < 0 or v >= self.shape[i]:
+ raise operationerrfmt(space.w_IndexError,
+ "index (%d) out of range (0<=index<%d", i, self.shape[i],
+ )
+ item += v * self.strides[i]
+ return item
+
+ @jit.unroll_safe
+ def _single_item_result(self, space, w_idx):
+ """ The result of getitem/setitem is a single item if w_idx
+ is a list of scalars that match the size of shape
+ """
+ shape_len = len(self.shape)
+ if shape_len == 0:
+ if not space.isinstance_w(w_idx, space.w_int):
+ raise OperationError(space.w_IndexError, space.wrap(
+ "wrong index"))
+ return True
+ if shape_len == 1:
+ if space.isinstance_w(w_idx, space.w_int):
+ return True
+ if space.isinstance_w(w_idx, space.w_slice):
+ return False
+ elif (space.isinstance_w(w_idx, space.w_slice) or
+ space.isinstance_w(w_idx, space.w_int)):
+ return False
+ lgt = space.len_w(w_idx)
+ if lgt > shape_len:
+ raise OperationError(space.w_IndexError,
+ space.wrap("invalid index"))
+ if lgt < shape_len:
+ return False
+ for w_item in space.fixedview(w_idx):
+ if space.isinstance_w(w_item, space.w_slice):
+ return False
+ return True
+
+ @jit.unroll_safe
+ def _prepare_slice_args(self, space, w_idx):
+ if (space.isinstance_w(w_idx, space.w_int) or
+ space.isinstance_w(w_idx, space.w_slice)):
+ return [space.decode_index4(w_idx, self.shape[0])]
+ return [space.decode_index4(w_item, self.shape[i]) for i, w_item in
+ enumerate(space.fixedview(w_idx))]
def descr_getitem(self, space, w_idx):
- # TODO: indexing by arrays and lists
- if space.isinstance_w(w_idx, space.w_tuple):
- length = space.len_w(w_idx)
- if length == 0:
- return space.wrap(self)
- if length > 1: # only one dimension for now.
- raise OperationError(space.w_IndexError,
- space.wrap("invalid index"))
- w_idx = space.getitem(w_idx, space.wrap(0))
- start, stop, step, slice_length = space.decode_index4(w_idx, self.find_size())
- if step == 0:
- # Single index
- return self.get_concrete().eval(start).wrap(space)
- else:
- # Slice
- new_sig = signature.Signature.find_sig([
- SingleDimSlice.signature, self.signature
- ])
- res = SingleDimSlice(start, stop, step, slice_length, self, new_sig)
- return space.wrap(res)
+ if self._single_item_result(space, w_idx):
+ concrete = self.get_concrete()
+ if len(concrete.shape) < 1:
+ raise OperationError(space.w_IndexError, space.wrap(
+ "0-d arrays can't be indexed"))
+ item = concrete._index_of_single_item(space, w_idx)
+ return concrete.getitem(item).wrap(space)
+ chunks = self._prepare_slice_args(space, w_idx)
+ return space.wrap(self.create_slice(space, chunks))
def descr_setitem(self, space, w_idx, w_value):
- # TODO: indexing by arrays and lists
self.invalidated()
- if space.isinstance_w(w_idx, space.w_tuple):
- length = space.len_w(w_idx)
- if length > 1: # only one dimension for now.
- raise OperationError(space.w_IndexError,
- space.wrap("invalid index"))
- if length == 0:
- w_idx = space.newslice(space.wrap(0),
- space.wrap(self.find_size()),
- space.wrap(1))
+ concrete = self.get_concrete()
+ if self._single_item_result(space, w_idx):
+ if len(concrete.shape) < 1:
+ raise OperationError(space.w_IndexError, space.wrap(
+ "0-d arrays can't be indexed"))
+ item = concrete._index_of_single_item(space, w_idx)
+ concrete.setitem_w(space, item, w_value)
+ return
+ if isinstance(w_value, BaseArray):
+ # for now we just copy if setting part of an array from part of
+ # itself. can be improved.
+ if (concrete.get_root_storage() ==
+ w_value.get_concrete().get_root_storage()):
+ w_value = w_value.descr_copy(space)
+ else:
+ w_value = convert_to_array(space, w_value)
+ chunks = self._prepare_slice_args(space, w_idx)
+ view = self.create_slice(space, chunks)
+ view.setslice(space, w_value)
+
+ @jit.unroll_safe
+ def create_slice(self, space, chunks):
+ if len(chunks) == 1:
+ start, stop, step, lgt = chunks[0]
+ if step == 0:
+ shape = self.shape[1:]
+ strides = self.strides[1:]
+ backstrides = self.backstrides[1:]
else:
- w_idx = space.getitem(w_idx, space.wrap(0))
- start, stop, step, slice_length = space.decode_index4(w_idx,
- self.find_size())
- if step == 0:
- # Single index
- self.get_concrete().setitem_w(space, start, w_value)
+ shape = [lgt] + self.shape[1:]
+ strides = [self.strides[0] * step] + self.strides[1:]
+ backstrides = [(lgt - 1) * self.strides[0] * step] + self.backstrides[1:]
+ start *= self.strides[0]
+ start += self.start
else:
- concrete = self.get_concrete()
- if isinstance(w_value, BaseArray):
- # for now we just copy if setting part of an array from
- # part of itself. can be improved.
- if (concrete.get_root_storage() ==
- w_value.get_concrete().get_root_storage()):
- w_value = space.call_function(space.gettypefor(BaseArray), w_value)
- assert isinstance(w_value, BaseArray)
- else:
- w_value = convert_to_array(space, w_value)
- concrete.setslice(space, start, stop, step,
- slice_length, w_value)
+ shape = []
+ strides = []
+ backstrides = []
+ start = self.start
+ i = -1
+ for i, (start_, stop, step, lgt) in enumerate(chunks):
+ if step != 0:
+ shape.append(lgt)
+ strides.append(self.strides[i] * step)
+ backstrides.append(self.strides[i] * (lgt - 1) * step)
+ start += self.strides[i] * start_
+ # add a reminder
+ s = i + 1
+ assert s >= 0
+ shape += self.shape[s:]
+ strides += self.strides[s:]
+ backstrides += self.backstrides[s:]
+ new_sig = signature.Signature.find_sig([
+ NDimSlice.signature, self.signature,
+ ])
+ return NDimSlice(self, new_sig, start, strides[:], backstrides[:],
+ shape[:])
def descr_mean(self, space):
- return space.wrap(space.float_w(self.descr_sum(space))/self.find_size())
+ return space.wrap(space.float_w(self.descr_sum(space)) / self.find_size())
- def _sliceloop(self, start, stop, step, source, dest):
- i = start
- j = 0
- while (step > 0 and i < stop) or (step < 0 and i > stop):
- slice_driver.jit_merge_point(signature=source.signature, step=step,
- stop=stop, i=i, j=j, source=source,
- dest=dest)
- dest.setitem(i, source.eval(j).convert_to(dest.find_dtype()))
- j += 1
- i += step
+ def descr_nonzero(self, space):
+ if self.find_size() > 1:
+ raise OperationError(space.w_ValueError, space.wrap(
+ "The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()"))
+ return space.wrap(space.is_true(self.get_concrete().eval(
+ self.start_iter(self.shape)).wrap(space)))
+
+ def descr_get_transpose(self, space):
+ concrete = self.get_concrete()
+ if len(concrete.shape) < 2:
+ return space.wrap(self)
+ new_sig = signature.Signature.find_sig([
+ NDimSlice.signature, self.signature
+ ])
+ strides = []
+ backstrides = []
+ shape = []
+ for i in range(len(concrete.shape) - 1, -1, -1):
+ strides.append(concrete.strides[i])
+ backstrides.append(concrete.backstrides[i])
+ shape.append(concrete.shape[i])
+ return space.wrap(NDimSlice(concrete, new_sig, self.start, strides[:],
+ backstrides[:], shape[:]))
+
+ def descr_get_flatiter(self, space):
+ return space.wrap(W_FlatIterator(self))
+
+ def getitem(self, item):
+ raise NotImplementedError
+
+ def start_iter(self, res_shape=None):
+ raise NotImplementedError
+
+ def descr_debug_repr(self, space):
+ return space.wrap(self.debug_repr())
def convert_to_array(space, w_obj):
if isinstance(w_obj, BaseArray):
@@ -309,36 +828,55 @@
return scalar_w(space, dtype, w_obj)
def scalar_w(space, dtype, w_obj):
+ assert isinstance(dtype, interp_dtype.W_Dtype)
return Scalar(dtype, dtype.unwrap(space, w_obj))
class Scalar(BaseArray):
"""
- Intermediate class representing a float literal.
+ Intermediate class representing a literal.
"""
signature = signature.BaseSignature()
- _attrs_ = ["dtype", "value"]
+ _attrs_ = ["dtype", "value", "shape"]
def __init__(self, dtype, value):
- BaseArray.__init__(self)
+ BaseArray.__init__(self, [], 'C')
self.dtype = dtype
self.value = value
def find_size(self):
- raise ValueError
+ return 1
+
+ def get_concrete(self):
+ return self
def find_dtype(self):
return self.dtype
- def eval(self, i):
+ def getitem(self, item):
+ raise NotImplementedError
+
+ def eval(self, iter):
return self.value
+ def start_iter(self, res_shape=None):
+ return ConstantIterator()
+
+ def to_str(self, space, comma, builder, indent=' ', use_ellipsis=False):
+ builder.append(self.dtype.str_format(self.value))
+
+ def copy(self):
+ return Scalar(self.dtype, self.value)
+
+ def debug_repr(self):
+ return 'Scalar'
+
class VirtualArray(BaseArray):
"""
Class for representing virtual arrays, such as binary ops or ufuncs
"""
- def __init__(self, signature, res_dtype):
- BaseArray.__init__(self)
+ def __init__(self, signature, shape, res_dtype, order):
+ BaseArray.__init__(self, shape, order)
self.forced_result = None
self.signature = signature
self.res_dtype = res_dtype
@@ -351,13 +889,18 @@
i = 0
signature = self.signature
result_size = self.find_size()
- result = SingleDimArray(result_size, self.find_dtype())
- while i < result_size:
+ result = NDimArray(result_size, self.shape, self.find_dtype())
+ shapelen = len(self.shape)
+ i = self.start_iter()
+ ri = result.start_iter()
+ while not ri.done():
numpy_driver.jit_merge_point(signature=signature,
- result_size=result_size, i=i,
+ shapelen=shapelen,
+ result_size=result_size, i=i, ri=ri,
self=self, result=result)
- result.dtype.setitem(result.storage, i, self.eval(i))
- i += 1
+ result.dtype.setitem(result.storage, ri.offset, self.eval(i))
+ i = i.next(shapelen)
+ ri = ri.next(shapelen)
return result
def force_if_needed(self):
@@ -369,10 +912,13 @@
self.force_if_needed()
return self.forced_result
- def eval(self, i):
+ def eval(self, iter):
if self.forced_result is not None:
- return self.forced_result.eval(i)
- return self._eval(i)
+ return self.forced_result.eval(iter)
+ return self._eval(iter)
+
+ def getitem(self, item):
+ return self.get_concrete().getitem(item)
def setitem(self, item, value):
return self.get_concrete().setitem(item, value)
@@ -388,8 +934,9 @@
class Call1(VirtualArray):
- def __init__(self, signature, res_dtype, values):
- VirtualArray.__init__(self, signature, res_dtype)
+ def __init__(self, signature, shape, res_dtype, values, order):
+ VirtualArray.__init__(self, signature, shape, res_dtype,
+ values.order)
self.values = values
def _del_sources(self):
@@ -401,53 +948,91 @@
def _find_dtype(self):
return self.res_dtype
- def _eval(self, i):
- val = self.values.eval(i).convert_to(self.res_dtype)
-
+ def _eval(self, iter):
+ assert isinstance(iter, Call1Iterator)
+ val = self.values.eval(iter.child).convert_to(self.res_dtype)
sig = jit.promote(self.signature)
assert isinstance(sig, signature.Signature)
call_sig = sig.components[0]
assert isinstance(call_sig, signature.Call1)
return call_sig.func(self.res_dtype, val)
+ def start_iter(self, res_shape=None):
+ if self.forced_result is not None:
+ return self.forced_result.start_iter(res_shape)
+ return Call1Iterator(self.values.start_iter(res_shape))
+
+ def debug_repr(self):
+ sig = self.signature
+ assert isinstance(sig, signature.Signature)
+ call_sig = sig.components[0]
+ assert isinstance(call_sig, signature.Call1)
+ if self.forced_result is not None:
+ return 'Call1(%s, forced=%s)' % (call_sig.func.func_name,
+ self.forced_result.debug_repr())
+ return 'Call1(%s, %s)' % (call_sig.func.func_name,
+ self.values.debug_repr())
+
class Call2(VirtualArray):
"""
Intermediate class for performing binary operations.
"""
- def __init__(self, signature, calc_dtype, res_dtype, left, right):
- VirtualArray.__init__(self, signature, res_dtype)
+ def __init__(self, signature, shape, calc_dtype, res_dtype, left, right):
+ # XXX do something if left.order != right.order
+ VirtualArray.__init__(self, signature, shape, res_dtype, left.order)
self.left = left
self.right = right
self.calc_dtype = calc_dtype
+ self.size = 1
+ for s in self.shape:
+ self.size *= s
def _del_sources(self):
self.left = None
self.right = None
def _find_size(self):
- try:
- return self.left.find_size()
- except ValueError:
- pass
- return self.right.find_size()
+ return self.size
- def _eval(self, i):
- lhs = self.left.eval(i).convert_to(self.calc_dtype)
- rhs = self.right.eval(i).convert_to(self.calc_dtype)
+ def start_iter(self, res_shape=None):
+ if self.forced_result is not None:
+ return self.forced_result.start_iter(res_shape)
+ if res_shape is None:
+ res_shape = self.shape # we still force the shape on children
+ return Call2Iterator(self.left.start_iter(res_shape),
+ self.right.start_iter(res_shape))
+ def _eval(self, iter):
+ assert isinstance(iter, Call2Iterator)
+ lhs = self.left.eval(iter.left).convert_to(self.calc_dtype)
+ rhs = self.right.eval(iter.right).convert_to(self.calc_dtype)
sig = jit.promote(self.signature)
assert isinstance(sig, signature.Signature)
call_sig = sig.components[0]
assert isinstance(call_sig, signature.Call2)
return call_sig.func(self.calc_dtype, lhs, rhs)
+ def debug_repr(self):
+ sig = self.signature
+ assert isinstance(sig, signature.Signature)
+ call_sig = sig.components[0]
+ assert isinstance(call_sig, signature.Call2)
+ if self.forced_result is not None:
+ return 'Call2(%s, forced=%s)' % (call_sig.func.func_name,
+ self.forced_result.debug_repr())
+ return 'Call2(%s, %s, %s)' % (call_sig.func.func_name,
+ self.left.debug_repr(),
+ self.right.debug_repr())
+
class ViewArray(BaseArray):
"""
Class for representing views of arrays, they will reflect changes of parent
arrays. Example: slices
"""
- def __init__(self, parent, signature):
- BaseArray.__init__(self)
+ def __init__(self, parent, signature, strides, backstrides, shape):
+ self.strides = strides
+ self.backstrides = backstrides
+ BaseArray.__init__(self, shape, parent.order)
self.signature = signature
self.parent = parent
self.invalidates = parent.invalidates
@@ -459,39 +1044,38 @@
self.parent.get_concrete()
return self
- def eval(self, i):
- return self.parent.eval(self.calc_index(i))
+ def getitem(self, item):
+ return self.parent.getitem(item)
+
+ def eval(self, iter):
+ return self.parent.getitem(iter.get_offset())
@unwrap_spec(item=int)
def setitem_w(self, space, item, w_value):
- return self.parent.setitem_w(space, self.calc_index(item), w_value)
+ return self.parent.setitem_w(space, item, w_value)
def setitem(self, item, value):
# This is currently not possible to be called from anywhere.
raise NotImplementedError
def descr_len(self, space):
- return space.wrap(self.find_size())
+ if self.shape:
+ return space.wrap(self.shape[0])
+ return space.wrap(1)
- def calc_index(self, item):
- raise NotImplementedError
-class SingleDimSlice(ViewArray):
+class NDimSlice(ViewArray):
signature = signature.BaseSignature()
- def __init__(self, start, stop, step, slice_length, parent, signature):
- ViewArray.__init__(self, parent, signature)
- if isinstance(parent, SingleDimSlice):
- self.start = parent.calc_index(start)
- self.stop = parent.calc_index(stop)
- self.step = parent.step * step
- self.parent = parent.parent
- else:
- self.start = start
- self.stop = stop
- self.step = step
- self.parent = parent
- self.size = slice_length
+ def __init__(self, parent, signature, start, strides, backstrides,
+ shape):
+ if isinstance(parent, NDimSlice):
+ parent = parent.parent
+ ViewArray.__init__(self, parent, signature, strides, backstrides, shape)
+ self.start = start
+ self.size = 1
+ for sh in shape:
+ self.size *= sh
def get_root_storage(self):
return self.parent.get_concrete().get_root_storage()
@@ -502,20 +1086,44 @@
def find_dtype(self):
return self.parent.find_dtype()
- def setslice(self, space, start, stop, step, slice_length, arr):
- start = self.calc_index(start)
- if stop != -1:
- stop = self.calc_index(stop)
- step = self.step * step
- self._sliceloop(start, stop, step, arr, self.parent)
+ def setslice(self, space, w_value):
+ res_shape = shape_agreement(space, self.shape, w_value.shape)
+ self._sliceloop(w_value, res_shape)
- def calc_index(self, item):
- return (self.start + item * self.step)
+ def _sliceloop(self, source, res_shape):
+ source_iter = source.start_iter(res_shape)
+ res_iter = self.start_iter(res_shape)
+ shapelen = len(res_shape)
+ while not res_iter.done():
+ slice_driver.jit_merge_point(signature=source.signature,
+ shapelen=shapelen,
+ self=self, source=source,
+ res_iter=res_iter,
+ source_iter=source_iter)
+ self.setitem(res_iter.offset, source.eval(source_iter).convert_to(
+ self.find_dtype()))
+ source_iter = source_iter.next(shapelen)
+ res_iter = res_iter.next(shapelen)
+ def start_iter(self, res_shape=None):
+ if res_shape is not None and res_shape != self.shape:
+ return BroadcastIterator(self, res_shape)
+ # XXX there is a possible optimization here with SingleDimViewIterator
+ # ignore for now
+ return ViewIterator(self)
-class SingleDimArray(BaseArray):
- def __init__(self, size, dtype):
- BaseArray.__init__(self)
+ def setitem(self, item, value):
+ self.parent.setitem(item, value)
+
+ def debug_repr(self):
+ return 'Slice(%s)' % self.parent.debug_repr()
+
+class NDimArray(BaseArray):
+ """ A class representing contiguous array. We know that each iteration
+ by say ufunc will increase the data index by one
+ """
+ def __init__(self, size, shape, dtype, order='C'):
+ BaseArray.__init__(self, shape, order)
self.size = size
self.dtype = dtype
self.storage = dtype.malloc(size)
@@ -533,11 +1141,26 @@
def find_dtype(self):
return self.dtype
- def eval(self, i):
- return self.dtype.getitem(self.storage, i)
+ def getitem(self, item):
+ return self.dtype.getitem(self.storage, item)
+
+ def eval(self, iter):
+ return self.dtype.getitem(self.storage, iter.get_offset())
+
+ def copy(self):
+ array = NDimArray(self.size, self.shape[:], self.dtype, self.order)
+ rffi.c_memcpy(
+ rffi.cast(rffi.VOIDP, array.storage),
+ rffi.cast(rffi.VOIDP, self.storage),
+ self.size * self.dtype.num_bytes
+ )
+ return array
def descr_len(self, space):
- return space.wrap(self.size)
+ if len(self.shape):
+ return space.wrap(self.shape[0])
+ raise OperationError(space.w_TypeError, space.wrap(
+ "len() of unsized object"))
def setitem_w(self, space, item, w_value):
self.invalidated()
@@ -547,30 +1170,55 @@
self.invalidated()
self.dtype.setitem(self.storage, item, value)
- def setslice(self, space, start, stop, step, slice_length, arr):
- self._sliceloop(start, stop, step, arr, self)
+ def start_iter(self, res_shape=None):
+ if self.order == 'C':
+ if res_shape is not None and res_shape != self.shape:
+ return BroadcastIterator(self, res_shape)
+ return ArrayIterator(self.size)
+ raise NotImplementedError # use ViewIterator simply, test it
+
+ def debug_repr(self):
+ return 'Array'
def __del__(self):
lltype.free(self.storage, flavor='raw', track_allocation=False)
- at unwrap_spec(size=int)
-def zeros(space, size, w_dtype=None):
+def _find_size_and_shape(space, w_size):
+ if space.isinstance_w(w_size, space.w_int):
+ size = space.int_w(w_size)
+ shape = [size]
+ else:
+ size = 1
+ shape = []
+ for w_item in space.fixedview(w_size):
+ item = space.int_w(w_item)
+ size *= item
+ shape.append(item)
+ return size, shape
+
+def zeros(space, w_size, w_dtype=None):
dtype = space.interp_w(interp_dtype.W_Dtype,
space.call_function(space.gettypefor(interp_dtype.W_Dtype), w_dtype)
)
- return space.wrap(SingleDimArray(size, dtype=dtype))
+ size, shape = _find_size_and_shape(space, w_size)
+ return space.wrap(NDimArray(size, shape[:], dtype=dtype))
- at unwrap_spec(size=int)
-def ones(space, size, w_dtype=None):
+def ones(space, w_size, w_dtype=None):
dtype = space.interp_w(interp_dtype.W_Dtype,
space.call_function(space.gettypefor(interp_dtype.W_Dtype), w_dtype)
)
-
- arr = SingleDimArray(size, dtype=dtype)
+ size, shape = _find_size_and_shape(space, w_size)
+ arr = NDimArray(size, shape[:], dtype=dtype)
one = dtype.adapt_val(1)
arr.dtype.fill(arr.storage, one, 0, size)
return space.wrap(arr)
+def dot(space, w_obj, w_obj2):
+ w_arr = convert_to_array(space, w_obj)
+ if isinstance(w_arr, Scalar):
+ return convert_to_array(space, w_obj2).descr_dot(space, w_arr)
+ return w_arr.descr_dot(space, w_obj2)
+
BaseArray.typedef = TypeDef(
'numarray',
__new__ = interp2app(descr_new_array),
@@ -583,6 +1231,7 @@
__pos__ = interp2app(BaseArray.descr_pos),
__neg__ = interp2app(BaseArray.descr_neg),
__abs__ = interp2app(BaseArray.descr_abs),
+ __nonzero__ = interp2app(BaseArray.descr_nonzero),
__add__ = interp2app(BaseArray.descr_add),
__sub__ = interp2app(BaseArray.descr_sub),
@@ -607,11 +1256,15 @@
__repr__ = interp2app(BaseArray.descr_repr),
__str__ = interp2app(BaseArray.descr_str),
+ __debug_repr__ = interp2app(BaseArray.descr_debug_repr),
dtype = GetSetProperty(BaseArray.descr_get_dtype),
shape = GetSetProperty(BaseArray.descr_get_shape),
size = GetSetProperty(BaseArray.descr_get_size),
+ T = GetSetProperty(BaseArray.descr_get_transpose),
+ flat = GetSetProperty(BaseArray.descr_get_flatiter),
+
mean = interp2app(BaseArray.descr_mean),
sum = interp2app(BaseArray.descr_sum),
prod = interp2app(BaseArray.descr_prod),
@@ -625,3 +1278,54 @@
copy = interp2app(BaseArray.descr_copy),
)
+
+
+class W_FlatIterator(ViewArray):
+ signature = signature.BaseSignature()
+
+ @jit.unroll_safe
+ def __init__(self, arr):
+ size = 1
+ for sh in arr.shape:
+ size *= sh
+ new_sig = signature.Signature.find_sig([
+ W_FlatIterator.signature, arr.signature
+ ])
+ ViewArray.__init__(self, arr, new_sig, [arr.strides[-1]],
+ [arr.backstrides[-1]], [size])
+ self.shapelen = len(arr.shape)
+ self.arr = arr
+ self.iter = self.start_iter()
+
+ def start_iter(self, res_shape=None):
+ if res_shape is not None and res_shape != self.shape:
+ return BroadcastIterator(self, res_shape)
+ return OneDimIterator(self.arr.start, self.strides[0],
+ self.shape[0])
+
+ def find_dtype(self):
+ return self.arr.find_dtype()
+
+ def find_size(self):
+ return self.shape[0]
+
+ def descr_next(self, space):
+ if self.iter.done():
+ raise OperationError(space.w_StopIteration, space.wrap(''))
+ result = self.eval(self.iter)
+ self.iter = self.iter.next(self.shapelen)
+ return result.wrap(space)
+
+ def descr_iter(self):
+ return self
+
+ def debug_repr(self):
+ return 'FlatIter(%s)' % self.arr.debug_repr()
+
+
+W_FlatIterator.typedef = TypeDef(
+ 'flatiter',
+ next = interp2app(W_FlatIterator.descr_next),
+ __iter__ = interp2app(W_FlatIterator.descr_iter),
+)
+W_FlatIterator.acceptable_as_base_class = False
diff --git a/pypy/module/micronumpy/interp_support.py b/pypy/module/micronumpy/interp_support.py
--- a/pypy/module/micronumpy/interp_support.py
+++ b/pypy/module/micronumpy/interp_support.py
@@ -9,7 +9,7 @@
@unwrap_spec(s=str)
def fromstring(space, s):
- from pypy.module.micronumpy.interp_numarray import SingleDimArray
+ from pypy.module.micronumpy.interp_numarray import NDimArray
length = len(s)
if length % FLOAT_SIZE == 0:
@@ -19,7 +19,7 @@
"string length %d not divisable by %d" % (length, FLOAT_SIZE)))
dtype = space.fromcache(W_Float64Dtype)
- a = SingleDimArray(number, dtype=dtype)
+ a = NDimArray(number, [number], dtype=dtype)
start = 0
end = FLOAT_SIZE
@@ -31,4 +31,4 @@
start += FLOAT_SIZE
end += FLOAT_SIZE
- return space.wrap(a)
\ No newline at end of file
+ return space.wrap(a)
diff --git a/pypy/module/micronumpy/interp_ufuncs.py b/pypy/module/micronumpy/interp_ufuncs.py
--- a/pypy/module/micronumpy/interp_ufuncs.py
+++ b/pypy/module/micronumpy/interp_ufuncs.py
@@ -1,6 +1,6 @@
from pypy.interpreter.baseobjspace import Wrappable
from pypy.interpreter.error import OperationError, operationerrfmt
-from pypy.interpreter.gateway import interp2app
+from pypy.interpreter.gateway import interp2app, unwrap_spec
from pypy.interpreter.typedef import TypeDef, GetSetProperty, interp_attrproperty
from pypy.module.micronumpy import interp_dtype, signature
from pypy.rlib import jit
@@ -9,8 +9,8 @@
reduce_driver = jit.JitDriver(
- greens = ["signature"],
- reds = ["i", "size", "self", "dtype", "value", "obj"]
+ greens = ['shapelen', "signature"],
+ reds = ["i", "self", "dtype", "value", "obj"]
)
class W_Ufunc(Wrappable):
@@ -45,8 +45,10 @@
return self.call(space, __args__.arguments_w)
def descr_reduce(self, space, w_obj):
+ return self.reduce(space, w_obj, multidim=False)
+
+ def reduce(self, space, w_obj, multidim):
from pypy.module.micronumpy.interp_numarray import convert_to_array, Scalar
-
if self.argcount != 2:
raise OperationError(space.w_ValueError, space.wrap("reduce only "
"supported for binary functions"))
@@ -62,28 +64,33 @@
space, obj.find_dtype(),
promote_to_largest=True
)
- start = 0
+ start = obj.start_iter(obj.shape)
+ shapelen = len(obj.shape)
+ if shapelen > 1 and not multidim:
+ raise OperationError(space.w_NotImplementedError,
+ space.wrap("not implemented yet"))
if self.identity is None:
if size == 0:
raise operationerrfmt(space.w_ValueError, "zero-size array to "
"%s.reduce without identity", self.name)
- value = obj.eval(0).convert_to(dtype)
- start += 1
+ value = obj.eval(start).convert_to(dtype)
+ start = start.next(shapelen)
else:
value = self.identity.convert_to(dtype)
new_sig = signature.Signature.find_sig([
self.reduce_signature, obj.signature
])
- return self.reduce(new_sig, start, value, obj, dtype, size).wrap(space)
+ return self.reduce_loop(new_sig, shapelen, start, value, obj,
+ dtype).wrap(space)
- def reduce(self, signature, start, value, obj, dtype, size):
- i = start
- while i < size:
- reduce_driver.jit_merge_point(signature=signature, self=self,
+ def reduce_loop(self, signature, shapelen, i, value, obj, dtype):
+ while not i.done():
+ reduce_driver.jit_merge_point(signature=signature,
+ shapelen=shapelen, self=self,
value=value, obj=obj, i=i,
- dtype=dtype, size=size)
+ dtype=dtype)
value = self.func(dtype, value, obj.eval(i).convert_to(dtype))
- i += 1
+ i = i.next(shapelen)
return value
class W_Ufunc1(W_Ufunc):
@@ -111,7 +118,7 @@
return self.func(res_dtype, w_obj.value.convert_to(res_dtype)).wrap(space)
new_sig = signature.Signature.find_sig([self.signature, w_obj.signature])
- w_res = Call1(new_sig, res_dtype, w_obj)
+ w_res = Call1(new_sig, w_obj.shape, res_dtype, w_obj, w_obj.order)
w_obj.add_invalidates(w_res)
return w_res
@@ -130,7 +137,7 @@
def call(self, space, args_w):
from pypy.module.micronumpy.interp_numarray import (Call2,
- convert_to_array, Scalar)
+ convert_to_array, Scalar, shape_agreement)
[w_lhs, w_rhs] = args_w
w_lhs = convert_to_array(space, w_lhs)
@@ -153,7 +160,9 @@
new_sig = signature.Signature.find_sig([
self.signature, w_lhs.signature, w_rhs.signature
])
- w_res = Call2(new_sig, calc_dtype, res_dtype, w_lhs, w_rhs)
+ new_shape = shape_agreement(space, w_lhs.shape, w_rhs.shape)
+ w_res = Call2(new_sig, new_shape, calc_dtype,
+ res_dtype, w_lhs, w_rhs)
w_lhs.add_invalidates(w_res)
w_rhs.add_invalidates(w_res)
return w_res
@@ -310,6 +319,8 @@
("floor", "floor", 1, {"promote_to_float": True}),
("exp", "exp", 1, {"promote_to_float": True}),
+ ('sqrt', 'sqrt', 1, {'promote_to_float': True}),
+
("sin", "sin", 1, {"promote_to_float": True}),
("cos", "cos", 1, {"promote_to_float": True}),
("tan", "tan", 1, {"promote_to_float": True}),
diff --git a/pypy/module/micronumpy/signature.py b/pypy/module/micronumpy/signature.py
--- a/pypy/module/micronumpy/signature.py
+++ b/pypy/module/micronumpy/signature.py
@@ -49,4 +49,4 @@
_immutable_fields_ = ["func"]
def __init__(self, func):
- self.func = func
\ No newline at end of file
+ self.func = func
diff --git a/pypy/module/micronumpy/test/test_base.py b/pypy/module/micronumpy/test/test_base.py
--- a/pypy/module/micronumpy/test/test_base.py
+++ b/pypy/module/micronumpy/test/test_base.py
@@ -1,6 +1,6 @@
from pypy.conftest import gettestobjspace
from pypy.module.micronumpy import interp_dtype
-from pypy.module.micronumpy.interp_numarray import SingleDimArray, Scalar
+from pypy.module.micronumpy.interp_numarray import NDimArray, Scalar
from pypy.module.micronumpy.interp_ufuncs import (find_binop_result_dtype,
find_unaryop_result_dtype)
@@ -13,7 +13,7 @@
def test_binop_signature(self, space):
float64_dtype = space.fromcache(interp_dtype.W_Float64Dtype)
- ar = SingleDimArray(10, dtype=float64_dtype)
+ ar = NDimArray(10, [10], dtype=float64_dtype)
v1 = ar.descr_add(space, ar)
v2 = ar.descr_add(space, Scalar(float64_dtype, 2.0))
assert v1.signature is not v2.signature
@@ -22,7 +22,7 @@
v4 = ar.descr_add(space, ar)
assert v1.signature is v4.signature
- bool_ar = SingleDimArray(10, dtype=space.fromcache(interp_dtype.W_BoolDtype))
+ bool_ar = NDimArray(10, [10], dtype=space.fromcache(interp_dtype.W_BoolDtype))
v5 = ar.descr_add(space, bool_ar)
assert v5.signature is not v1.signature
assert v5.signature is not v2.signature
@@ -30,13 +30,13 @@
assert v5.signature is v6.signature
def test_slice_signature(self, space):
- ar = SingleDimArray(10, dtype=space.fromcache(interp_dtype.W_Float64Dtype))
- v1 = ar.descr_getitem(space, space.wrap(slice(1, 5, 1)))
+ ar = NDimArray(10, [10], dtype=space.fromcache(interp_dtype.W_Float64Dtype))
+ v1 = ar.descr_getitem(space, space.wrap(slice(1, 3, 1)))
v2 = ar.descr_getitem(space, space.wrap(slice(4, 6, 1)))
assert v1.signature is v2.signature
- v3 = ar.descr_add(space, v1)
- v4 = ar.descr_add(space, v2)
+ v3 = v2.descr_add(space, v1)
+ v4 = v1.descr_add(space, v2)
assert v3.signature is v4.signature
class TestUfuncCoerscion(object):
diff --git a/pypy/module/micronumpy/test/test_compile.py b/pypy/module/micronumpy/test/test_compile.py
--- a/pypy/module/micronumpy/test/test_compile.py
+++ b/pypy/module/micronumpy/test/test_compile.py
@@ -5,7 +5,7 @@
class TestCompiler(object):
def compile(self, code):
return numpy_compile(code)
-
+
def test_vars(self):
code = """
a = 2
@@ -25,7 +25,7 @@
st = interp.code.statements[0]
assert st.expr.items == [FloatConstant(1), FloatConstant(2),
FloatConstant(3)]
-
+
def test_array_literal2(self):
code = "a = [[1],[2],[3]]"
interp = self.compile(code)
@@ -102,10 +102,11 @@
code = """
a = [1,2,3,4]
b = [4,5,6,5]
- a + b
+ c = a + b
+ c -> 3
"""
interp = self.run(code)
- assert interp.results[0]._getnums(False) == ["5.0", "7.0", "9.0", "9.0"]
+ assert interp.results[-1].value.val == 9
def test_array_getitem(self):
code = """
@@ -115,7 +116,7 @@
"""
interp = self.run(code)
assert interp.results[0].value.val == 3 + 6
-
+
def test_range_getitem(self):
code = """
r = |20| + 3
@@ -161,10 +162,32 @@
assert interp.results[0].value.val == 256
def test_slice(self):
- py.test.skip("in progress")
interp = self.run("""
a = [1,2,3,4]
b = a -> :
b -> 3
""")
- assert interp.results[0].value.val == 3
+ assert interp.results[0].value.val == 4
+
+ def test_slice_step(self):
+ interp = self.run("""
+ a = |30|
+ b = a -> ::2
+ b -> 3
+ """)
+ assert interp.results[0].value.val == 6
+
+ def test_multidim_getitem(self):
+ interp = self.run("""
+ a = [[1,2]]
+ a -> 0 -> 1
+ """)
+ assert interp.results[0].value.val == 2
+
+ def test_multidim_getitem_2(self):
+ interp = self.run("""
+ a = [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]]
+ b = a + a
+ b -> 1 -> 1
+ """)
+ assert interp.results[0].value.val == 8
diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py
--- a/pypy/module/micronumpy/test/test_numarray.py
+++ b/pypy/module/micronumpy/test/test_numarray.py
@@ -1,7 +1,164 @@
+
+import py
from pypy.module.micronumpy.test.test_base import BaseNumpyAppTest
+from pypy.module.micronumpy.interp_numarray import NDimArray, shape_agreement
+from pypy.module.micronumpy import signature
+from pypy.interpreter.error import OperationError
from pypy.conftest import gettestobjspace
+class MockDtype(object):
+ signature = signature.BaseSignature()
+
+ def malloc(self, size):
+ return None
+
+
+class TestNumArrayDirect(object):
+ def newslice(self, *args):
+ return self.space.newslice(*[self.space.wrap(arg) for arg in args])
+
+ def newtuple(self, *args):
+ args_w = []
+ for arg in args:
+ if isinstance(arg, int):
+ args_w.append(self.space.wrap(arg))
+ else:
+ args_w.append(arg)
+ return self.space.newtuple(args_w)
+
+ def test_strides_f(self):
+ a = NDimArray(100, [10, 5, 3], MockDtype(), 'F')
+ assert a.strides == [1, 10, 50]
+ assert a.backstrides == [9, 40, 100]
+
+ def test_strides_c(self):
+ a = NDimArray(100, [10, 5, 3], MockDtype(), 'C')
+ assert a.strides == [15, 3, 1]
+ assert a.backstrides == [135, 12, 2]
+
+ def test_create_slice_f(self):
+ space = self.space
+ a = NDimArray(10 * 5 * 3, [10, 5, 3], MockDtype(), 'F')
+ s = a.create_slice(space, [(3, 0, 0, 1)])
+ assert s.start == 3
+ assert s.strides == [10, 50]
+ assert s.backstrides == [40, 100]
+ s = a.create_slice(space, [(1, 9, 2, 4)])
+ assert s.start == 1
+ assert s.strides == [2, 10, 50]
+ assert s.backstrides == [6, 40, 100]
+ s = a.create_slice(space, [(1, 5, 3, 2), (1, 2, 1, 1), (1, 0, 0, 1)])
+ assert s.shape == [2, 1]
+ assert s.strides == [3, 10]
+ assert s.backstrides == [3, 0]
+ s = a.create_slice(space, [(0, 10, 1, 10), (2, 0, 0, 1)])
+ assert s.start == 20
+ assert s.shape == [10, 3]
+
+ def test_create_slice_c(self):
+ space = self.space
+ a = NDimArray(10 * 5 * 3, [10, 5, 3], MockDtype(), 'C')
+ s = a.create_slice(space, [(3, 0, 0, 1)])
+ assert s.start == 45
+ assert s.strides == [3, 1]
+ assert s.backstrides == [12, 2]
+ s = a.create_slice(space, [(1, 9, 2, 4)])
+ assert s.start == 15
+ assert s.strides == [30, 3, 1]
+ assert s.backstrides == [90, 12, 2]
+ s = a.create_slice(space, [(1, 5, 3, 2), (1, 2, 1, 1), (1, 0, 0, 1)])
+ assert s.start == 19
+ assert s.shape == [2, 1]
+ assert s.strides == [45, 3]
+ assert s.backstrides == [45, 0]
+ s = a.create_slice(space, [(0, 10, 1, 10), (2, 0, 0, 1)])
+ assert s.start == 6
+ assert s.shape == [10, 3]
+
+ def test_slice_of_slice_f(self):
+ space = self.space
+ a = NDimArray(10 * 5 * 3, [10, 5, 3], MockDtype(), 'F')
+ s = a.create_slice(space, [(5, 0, 0, 1)])
+ assert s.start == 5
+ s2 = s.create_slice(space, [(3, 0, 0, 1)])
+ assert s2.shape == [3]
+ assert s2.strides == [50]
+ assert s2.parent is a
+ assert s2.backstrides == [100]
+ assert s2.start == 35
+ s = a.create_slice(space, [(1, 5, 3, 2)])
+ s2 = s.create_slice(space, [(0, 2, 1, 2), (2, 0, 0, 1)])
+ assert s2.shape == [2, 3]
+ assert s2.strides == [3, 50]
+ assert s2.backstrides == [3, 100]
+ assert s2.start == 1 * 15 + 2 * 3
+
+ def test_slice_of_slice_c(self):
+ space = self.space
+ a = NDimArray(10 * 5 * 3, [10, 5, 3], MockDtype(), order='C')
+ s = a.create_slice(space, [(5, 0, 0, 1)])
+ assert s.start == 15 * 5
+ s2 = s.create_slice(space, [(3, 0, 0, 1)])
+ assert s2.shape == [3]
+ assert s2.strides == [1]
+ assert s2.parent is a
+ assert s2.backstrides == [2]
+ assert s2.start == 5 * 15 + 3 * 3
+ s = a.create_slice(space, [(1, 5, 3, 2)])
+ s2 = s.create_slice(space, [(0, 2, 1, 2), (2, 0, 0, 1)])
+ assert s2.shape == [2, 3]
+ assert s2.strides == [45, 1]
+ assert s2.backstrides == [45, 2]
+ assert s2.start == 1 * 15 + 2 * 3
+
+ def test_negative_step_f(self):
+ space = self.space
+ a = NDimArray(10 * 5 * 3, [10, 5, 3], MockDtype(), 'F')
+ s = a.create_slice(space, [(9, -1, -2, 5)])
+ assert s.start == 9
+ assert s.strides == [-2, 10, 50]
+ assert s.backstrides == [-8, 40, 100]
+
+ def test_negative_step_c(self):
+ space = self.space
+ a = NDimArray(10 * 5 * 3, [10, 5, 3], MockDtype(), order='C')
+ s = a.create_slice(space, [(9, -1, -2, 5)])
+ assert s.start == 135
+ assert s.strides == [-30, 3, 1]
+ assert s.backstrides == [-120, 12, 2]
+
+ def test_index_of_single_item_f(self):
+ a = NDimArray(10 * 5 * 3, [10, 5, 3], MockDtype(), 'F')
+ r = a._index_of_single_item(self.space, self.newtuple(1, 2, 2))
+ assert r == 1 + 2 * 10 + 2 * 50
+ s = a.create_slice(self.space, [(0, 10, 1, 10), (2, 0, 0, 1)])
+ r = s._index_of_single_item(self.space, self.newtuple(1, 0))
+ assert r == a._index_of_single_item(self.space, self.newtuple(1, 2, 0))
+ r = s._index_of_single_item(self.space, self.newtuple(1, 1))
+ assert r == a._index_of_single_item(self.space, self.newtuple(1, 2, 1))
+
+ def test_index_of_single_item_c(self):
+ a = NDimArray(10 * 5 * 3, [10, 5, 3], MockDtype(), 'C')
+ r = a._index_of_single_item(self.space, self.newtuple(1, 2, 2))
+ assert r == 1 * 3 * 5 + 2 * 3 + 2
+ s = a.create_slice(self.space, [(0, 10, 1, 10), (2, 0, 0, 1)])
+ r = s._index_of_single_item(self.space, self.newtuple(1, 0))
+ assert r == a._index_of_single_item(self.space, self.newtuple(1, 2, 0))
+ r = s._index_of_single_item(self.space, self.newtuple(1, 1))
+ assert r == a._index_of_single_item(self.space, self.newtuple(1, 2, 1))
+
+ def test_shape_agreement(self):
+ assert shape_agreement(self.space, [3], [3]) == [3]
+ assert shape_agreement(self.space, [1, 2, 3], [1, 2, 3]) == [1, 2, 3]
+ py.test.raises(OperationError, shape_agreement, self.space, [2], [3])
+ assert shape_agreement(self.space, [4, 4], []) == [4, 4]
+ assert shape_agreement(self.space,
+ [8, 1, 6, 1], [7, 1, 5]) == [8, 7, 6, 5]
+ assert shape_agreement(self.space,
+ [5, 2], [4, 3, 5, 2]) == [4, 3, 5, 2]
+
+
class AppTestNumArray(BaseNumpyAppTest):
def test_type(self):
from numpypy import array
@@ -50,64 +207,17 @@
b = a.copy()
for i in xrange(5):
assert b[i] == a[i]
+ a[3] = 22
+ assert b[3] == 3
+
+ a = array(1)
+ assert a.copy() == a
def test_iterator_init(self):
from numpypy import array
a = array(range(5))
assert a[3] == 3
- def test_repr(self):
- from numpypy import array, zeros
- a = array(range(5), float)
- assert repr(a) == "array([0.0, 1.0, 2.0, 3.0, 4.0])"
- a = array([], float)
- assert repr(a) == "array([], dtype=float64)"
- a = zeros(1001)
- assert repr(a) == "array([0.0, 0.0, 0.0, ..., 0.0, 0.0, 0.0])"
- a = array(range(5), long)
- assert repr(a) == "array([0, 1, 2, 3, 4])"
- a = array([], long)
- assert repr(a) == "array([], dtype=int64)"
- a = array([True, False, True, False], "?")
- assert repr(a) == "array([True, False, True, False], dtype=bool)"
-
- def test_repr_slice(self):
- from numpypy import array, zeros
- a = array(range(5), float)
- b = a[1::2]
- assert repr(b) == "array([1.0, 3.0])"
- a = zeros(2002)
- b = a[::2]
- assert repr(b) == "array([0.0, 0.0, 0.0, ..., 0.0, 0.0, 0.0])"
-
- def test_str(self):
- from numpypy import array, zeros
- a = array(range(5), float)
- assert str(a) == "[0.0 1.0 2.0 3.0 4.0]"
- assert str((2*a)[:]) == "[0.0 2.0 4.0 6.0 8.0]"
- a = zeros(1001)
- assert str(a) == "[0.0 0.0 0.0 ..., 0.0 0.0 0.0]"
-
- a = array(range(5), dtype=long)
- assert str(a) == "[0 1 2 3 4]"
- a = array([True, False, True, False], dtype="?")
- assert str(a) == "[True False True False]"
-
- a = array(range(5), dtype="int8")
- assert str(a) == "[0 1 2 3 4]"
-
- a = array(range(5), dtype="int16")
- assert str(a) == "[0 1 2 3 4]"
-
- def test_str_slice(self):
- from numpypy import array, zeros
- a = array(range(5), float)
- b = a[1::2]
- assert str(b) == "[1.0 3.0]"
- a = zeros(2002)
- b = a[::2]
- assert str(b) == "[0.0 0.0 0.0 ..., 0.0 0.0 0.0]"
-
def test_getitem(self):
from numpypy import array
a = array(range(5))
@@ -140,8 +250,8 @@
a = array(range(5))
raises(IndexError, "a[(1,2)] = [0,1]")
for i in xrange(5):
- a[(i,)] = i+1
- assert a[i] == i+1
+ a[(i,)] = i + 1
+ assert a[i] == i + 1
a[()] = range(5)
for i in xrange(5):
assert a[i] == i
@@ -171,7 +281,7 @@
assert a[3] == 1.
assert a[4] == 11.
a = zeros(10)
- a[::2][::-1][::2] = array(range(1,4))
+ a[::2][::-1][::2] = array(range(1, 4))
assert a[8] == 1.
assert a[4] == 2.
assert a[0] == 3.
@@ -191,6 +301,14 @@
assert a[1] == 0.
assert a[3] == 0.
+ def test_scalar(self):
+ from numpypy import array
+ a = array(3)
+ #assert a[0] == 3
+ raises(IndexError, "a[0]")
+ assert a.size == 1
+ assert a.shape == ()
+
def test_len(self):
from numpypy import array
a = array(range(5))
@@ -222,7 +340,7 @@
def test_add_other(self):
from numpypy import array
a = array(range(5))
- b = array(range(4, -1, -1))
+ b = array([i for i in reversed(range(5))])
c = a + b
for i in range(5):
assert c[i] == 4
@@ -346,8 +464,10 @@
a = array(range(5), float)
b = a ** a
for i in range(5):
- print b[i], i**i
- assert b[i] == i**i
+ assert b[i] == i ** i
+
+ a = array(range(5))
+ assert (a ** 2 == a * a).all()
def test_pow_other(self):
from numpypy import array
@@ -366,7 +486,7 @@
def test_mod(self):
from numpypy import array
- a = array(range(1,6))
+ a = array(range(1, 6))
b = a % a
for i in range(5):
assert b[i] == 0
@@ -394,7 +514,7 @@
def test_pos(self):
from numpypy import array
- a = array([1.,-2.,3.,-4.,-5.])
+ a = array([1., -2., 3., -4., -5.])
b = +a
for i in range(5):
assert b[i] == a[i]
@@ -405,7 +525,7 @@
def test_neg(self):
from numpypy import array
- a = array([1.,-2.,3.,-4.,-5.])
+ a = array([1., -2., 3., -4., -5.])
b = -a
for i in range(5):
assert b[i] == -a[i]
@@ -416,7 +536,7 @@
def test_abs(self):
from numpypy import array
- a = array([1.,-2.,3.,-4.,-5.])
+ a = array([1., -2., 3., -4., -5.])
b = abs(a)
for i in range(5):
assert b[i] == abs(a[i])
@@ -445,7 +565,7 @@
s = a[1:5]
assert len(s) == 4
for i in range(4):
- assert s[i] == a[i+1]
+ assert s[i] == a[i + 1]
s = (a + a)[1:2]
assert len(s) == 1
@@ -459,7 +579,7 @@
s = a[1:9:2]
assert len(s) == 4
for i in range(4):
- assert s[i] == a[2*i+1]
+ assert s[i] == a[2 * i + 1]
def test_slice_update(self):
from numpypy import array
@@ -470,13 +590,12 @@
a[2] = 20
assert s[2] == 20
-
def test_slice_invaidate(self):
# check that slice shares invalidation list with
from numpypy import array
a = array(range(5))
s = a[0:2]
- b = array([10,11])
+ b = array([10, 11])
c = s + b
a[0] = 100
assert c[0] == 10
@@ -503,7 +622,7 @@
def test_prod(self):
from numpypy import array
- a = array(range(1,6))
+ a = array(range(1, 6))
assert a.prod() == 120.0
assert a[:4].prod() == 24.0
@@ -517,7 +636,7 @@
def test_max_add(self):
from numpypy import array
a = array([-1.2, 3.4, 5.7, -3.0, 2.7])
- assert (a+a).max() == 11.4
+ assert (a + a).max() == 11.4
def test_min(self):
from numpypy import array
@@ -529,12 +648,23 @@
def test_argmax(self):
from numpypy import array
a = array([-1.2, 3.4, 5.7, -3.0, 2.7])
- assert a.argmax() == 2
+ r = a.argmax()
+ assert r == 2
b = array([])
- raises(ValueError, "b.argmax()")
+ raises(ValueError, b.argmax)
a = array(range(-5, 5))
- assert a.argmax() == 9
+ r = a.argmax()
+ assert r == 9
+ b = a[::2]
+ r = b.argmax()
+ assert r == 4
+ r = (a + a).argmax()
+ assert r == 9
+ a = array([1, 0, 0])
+ assert a.argmax() == 0
+ a = array([0, 0, 1])
+ assert a.argmax() == 2
def test_argmin(self):
from numpypy import array
@@ -562,12 +692,14 @@
assert c.any() == False
def test_dot(self):
- from numpypy import array
+ from numpypy import array, dot
a = array(range(5))
assert a.dot(a) == 30.0
a = array(range(5))
assert a.dot(range(5)) == 30
+ assert dot(range(5), range(5)) == 30
+ assert (dot(5, [1, 2, 3]) == [5, 10, 15]).all()
def test_dot_constant(self):
from numpypy import array
@@ -608,6 +740,258 @@
for i in xrange(5):
assert c[i] == func(b[i], 3)
+ def test_nonzero(self):
+ from numpypy import array
+ a = array([1, 2])
+ raises(ValueError, bool, a)
+ raises(ValueError, bool, a == a)
+ assert bool(array(1))
+ assert not bool(array(0))
+ assert bool(array([1]))
+ assert not bool(array([0]))
+
+
+class AppTestMultiDim(BaseNumpyAppTest):
+ def test_init(self):
+ import numpypy
+ a = numpypy.zeros((2, 2))
+ assert len(a) == 2
+
+ def test_shape(self):
+ import numpypy
+ assert numpypy.zeros(1).shape == (1,)
+ assert numpypy.zeros((2, 2)).shape == (2, 2)
+ assert numpypy.zeros((3, 1, 2)).shape == (3, 1, 2)
+ assert numpypy.array([[1], [2], [3]]).shape == (3, 1)
+ assert len(numpypy.zeros((3, 1, 2))) == 3
+ raises(TypeError, len, numpypy.zeros(()))
+ raises(ValueError, numpypy.array, [[1, 2], 3])
+
+ def test_getsetitem(self):
+ import numpypy
+ a = numpypy.zeros((2, 3, 1))
+ raises(IndexError, a.__getitem__, (2, 0, 0))
+ raises(IndexError, a.__getitem__, (0, 3, 0))
+ raises(IndexError, a.__getitem__, (0, 0, 1))
+ assert a[1, 1, 0] == 0
+ a[1, 2, 0] = 3
+ assert a[1, 2, 0] == 3
+ assert a[1, 1, 0] == 0
+ assert a[1, -1, 0] == 3
+
+ def test_slices(self):
+ import numpypy
+ a = numpypy.zeros((4, 3, 2))
+ raises(IndexError, a.__getitem__, (4,))
+ raises(IndexError, a.__getitem__, (3, 3))
+ raises(IndexError, a.__getitem__, (slice(None), 3))
+ a[0, 1, 1] = 13
+ a[1, 2, 1] = 15
+ b = a[0]
+ assert len(b) == 3
+ assert b.shape == (3, 2)
+ assert b[1, 1] == 13
+ b = a[1]
+ assert b.shape == (3, 2)
+ assert b[2, 1] == 15
+ b = a[:, 1]
+ assert b.shape == (4, 2)
+ assert b[0, 1] == 13
+ b = a[:, 1, :]
+ assert b.shape == (4, 2)
+ assert b[0, 1] == 13
+ b = a[1, 2]
+ assert b[1] == 15
+ b = a[:]
+ assert b.shape == (4, 3, 2)
+ assert b[1, 2, 1] == 15
+ assert b[0, 1, 1] == 13
+ b = a[:][:, 1][:]
+ assert b[2, 1] == 0.0
+ assert b[0, 1] == 13
+ raises(IndexError, b.__getitem__, (4, 1))
+ assert a[0][1][1] == 13
+ assert a[1][2][1] == 15
+
+ def test_init_2(self):
+ import numpypy
+ raises(ValueError, numpypy.array, [[1], 2])
+ raises(ValueError, numpypy.array, [[1, 2], [3]])
+ raises(ValueError, numpypy.array, [[[1, 2], [3, 4], 5]])
+ raises(ValueError, numpypy.array, [[[1, 2], [3, 4], [5]]])
+ a = numpypy.array([[1, 2], [4, 5]])
+ assert a[0, 1] == 2
+ assert a[0][1] == 2
+ a = numpypy.array(([[[1, 2], [3, 4], [5, 6]]]))
+ assert (a[0, 1] == [3, 4]).all()
+
+ def test_setitem_slice(self):
+ import numpypy
+ a = numpypy.zeros((3, 4))
+ a[1] = [1, 2, 3, 4]
+ assert a[1, 2] == 3
+ raises(TypeError, a[1].__setitem__, [1, 2, 3])
+ a = numpypy.array([[1, 2], [3, 4]])
+ assert (a == [[1, 2], [3, 4]]).all()
+ a[1] = numpypy.array([5, 6])
+ assert (a == [[1, 2], [5, 6]]).all()
+ a[:, 1] = numpypy.array([8, 10])
+ assert (a == [[1, 8], [5, 10]]).all()
+ a[0, :: -1] = numpypy.array([11, 12])
+ assert (a == [[12, 11], [5, 10]]).all()
+
+ def test_ufunc(self):
+ from numpypy import array
+ a = array([[1, 2], [3, 4], [5, 6]])
+ assert ((a + a) == \
+ array([[1 + 1, 2 + 2], [3 + 3, 4 + 4], [5 + 5, 6 + 6]])).all()
+
+ def test_getitem_add(self):
+ from numpypy import array
+ a = array([[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]])
+ assert (a + a)[1, 1] == 8
+
+ def test_ufunc_negative(self):
+ from numpypy import array, negative
+ a = array([[1, 2], [3, 4]])
+ b = negative(a + a)
+ assert (b == [[-2, -4], [-6, -8]]).all()
+
+ def test_getitem_3(self):
+ from numpypy import array
+ a = array([[1, 2], [3, 4], [5, 6], [7, 8],
+ [9, 10], [11, 12], [13, 14]])
+ b = a[::2]
+ print a
+ print b
+ assert (b == [[1, 2], [5, 6], [9, 10], [13, 14]]).all()
+ c = b + b
+ assert c[1][1] == 12
+
+ def test_multidim_ones(self):
+ from numpypy import ones
+ a = ones((1, 2, 3))
+ assert a[0, 1, 2] == 1.0
+
+ def test_broadcast_ufunc(self):
+ from numpypy import array
+ a = array([[1, 2], [3, 4], [5, 6]])
+ b = array([5, 6])
+ c = ((a + b) == [[1 + 5, 2 + 6], [3 + 5, 4 + 6], [5 + 5, 6 + 6]])
+ assert c.all()
+
+ def test_broadcast_setslice(self):
+ from numpypy import zeros, ones
+ a = zeros((100, 100))
+ b = ones(100)
+ a[:, :] = b
+ assert a[13, 15] == 1
+
+ def test_broadcast_shape_agreement(self):
+ from numpypy import zeros, array
+ a = zeros((3, 1, 3))
+ b = array(((10, 11, 12), (20, 21, 22), (30, 31, 32)))
+ c = ((a + b) == [b, b, b])
+ assert c.all()
+ a = array((((10, 11, 12), ), ((20, 21, 22), ), ((30, 31, 32), )))
+ assert(a.shape == (3, 1, 3))
+ d = zeros((3, 3))
+ c = ((a + d) == [b, b, b])
+ c = ((a + d) == array([[[10., 11., 12.]] * 3,
+ [[20., 21., 22.]] * 3, [[30., 31., 32.]] * 3]))
+ assert c.all()
+
+ def test_broadcast_scalar(self):
+ from numpypy import zeros
+ a = zeros((4, 5), 'd')
+ a[:, 1] = 3
+ assert a[2, 1] == 3
+ assert a[0, 2] == 0
+ a[0, :] = 5
+ assert a[0, 3] == 5
+ assert a[2, 1] == 3
+ assert a[3, 2] == 0
+
+ def test_broadcast_call2(self):
+ from numpypy import zeros, ones
+ a = zeros((4, 1, 5))
+ b = ones((4, 3, 5))
+ b[:] = (a + a)
+ assert (b == zeros((4, 3, 5))).all()
+
+ def test_argmax(self):
+ from numpypy import array
+ a = array([[1, 2], [3, 4], [5, 6]])
+ assert a.argmax() == 5
+ assert a[:2, ].argmax() == 3
+
+ def test_broadcast_wrong_shapes(self):
+ from numpypy import zeros
+ a = zeros((4, 3, 2))
+ b = zeros((4, 2))
+ exc = raises(ValueError, lambda: a + b)
+ assert str(exc.value) == "operands could not be broadcast" \
+ " together with shapes (4,3,2) (4,2)"
+
+ def test_reduce(self):
+ from numpypy import array
+ a = array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])
+ assert a.sum() == (13 * 12) / 2
+ b = a[1:, 1::2]
+ c = b + b
+ assert c.sum() == (6 + 8 + 10 + 12) * 2
+
+ def test_transpose(self):
+ from numpypy import array
+ a = array(((range(3), range(3, 6)),
+ (range(6, 9), range(9, 12)),
+ (range(12, 15), range(15, 18)),
+ (range(18, 21), range(21, 24))))
+ assert a.shape == (4, 2, 3)
+ b = a.T
+ assert b.shape == (3, 2, 4)
+ assert(b[0, :, 0] == [0, 3]).all()
+ b[:, 0, 0] = 1000
+ assert(a[0, 0, :] == [1000, 1000, 1000]).all()
+ a = array(range(5))
+ b = a.T
+ assert(b == range(5)).all()
+ a = array((range(10), range(20, 30)))
+ b = a.T
+ assert(b[:, 0] == a[0, :]).all()
+
+ def test_flatiter(self):
+ from numpypy import array, flatiter
+ a = array([[10, 30], [40, 60]])
+ f_iter = a.flat
+ assert f_iter.next() == 10
+ assert f_iter.next() == 30
+ assert f_iter.next() == 40
+ assert f_iter.next() == 60
+ raises(StopIteration, "f_iter.next()")
+ raises(TypeError, "flatiter()")
+ s = 0
+ for k in a.flat:
+ s += k
+ assert s == 140
+
+ def test_flatiter_array_conv(self):
+ from numpypy import array, dot
+ a = array([1, 2, 3])
+ assert dot(a.flat, a.flat) == 14
+
+ def test_debug_repr(self):
+ from numpypy import zeros, sin
+ a = zeros(1)
+ assert a.__debug_repr__() == 'Array'
+ assert (a + a).__debug_repr__() == 'Call2(add, Array, Array)'
+ assert (a[::2]).__debug_repr__() == 'Slice(Array)'
+ assert (a + 2).__debug_repr__() == 'Call2(add, Array, Scalar)'
+ assert (a + a.flat).__debug_repr__() == 'Call2(add, Array, FlatIter(Array))'
+ assert sin(a).__debug_repr__() == 'Call1(sin, Array)'
+ b = a + a
+ b[0] = 3
+ assert b.__debug_repr__() == 'Call2(add, forced=Array)'
class AppTestSupport(object):
def setup_class(cls):
@@ -621,3 +1005,119 @@
for i in range(4):
assert a[i] == i + 1
raises(ValueError, fromstring, "abc")
+
+
+class AppTestRepr(BaseNumpyAppTest):
+ def test_repr(self):
+ from numpypy import array, zeros
+ a = array(range(5), float)
+ assert repr(a) == "array([0.0, 1.0, 2.0, 3.0, 4.0])"
+ a = array([], float)
+ assert repr(a) == "array([], dtype=float64)"
+ a = zeros(1001)
+ assert repr(a) == "array([0.0, 0.0, 0.0, ..., 0.0, 0.0, 0.0])"
+ a = array(range(5), long)
+ assert repr(a) == "array([0, 1, 2, 3, 4])"
+ a = array([], long)
+ assert repr(a) == "array([], dtype=int64)"
+ a = array([True, False, True, False], "?")
+ assert repr(a) == "array([True, False, True, False], dtype=bool)"
+
+ def test_repr_multi(self):
+ from numpypy import array, zeros
+ a = zeros((3, 4))
+ assert repr(a) == '''array([[0.0, 0.0, 0.0, 0.0],
+ [0.0, 0.0, 0.0, 0.0],
+ [0.0, 0.0, 0.0, 0.0]])'''
+ a = zeros((2, 3, 4))
+ assert repr(a) == '''array([[[0.0, 0.0, 0.0, 0.0],
+ [0.0, 0.0, 0.0, 0.0],
+ [0.0, 0.0, 0.0, 0.0]],
+
+ [[0.0, 0.0, 0.0, 0.0],
+ [0.0, 0.0, 0.0, 0.0],
+ [0.0, 0.0, 0.0, 0.0]]])'''
+
+ def test_repr_slice(self):
+ from numpypy import array, zeros
+ a = array(range(5), float)
+ b = a[1::2]
+ assert repr(b) == "array([1.0, 3.0])"
+ a = zeros(2002)
+ b = a[::2]
+ assert repr(b) == "array([0.0, 0.0, 0.0, ..., 0.0, 0.0, 0.0])"
+ a = array((range(5), range(5, 10)), dtype="int16")
+ b = a[1, 2:]
+ assert repr(b) == "array([7, 8, 9], dtype=int16)"
+ # an empty slice prints its shape
+ b = a[2:1, ]
+ assert repr(b) == "array([], shape=(0, 5), dtype=int16)"
+
+ def test_str(self):
+ from numpypy import array, zeros
+ a = array(range(5), float)
+ assert str(a) == "[0.0 1.0 2.0 3.0 4.0]"
+ assert str((2 * a)[:]) == "[0.0 2.0 4.0 6.0 8.0]"
+ a = zeros(1001)
+ assert str(a) == "[0.0 0.0 0.0 ..., 0.0 0.0 0.0]"
+
+ a = array(range(5), dtype=long)
+ assert str(a) == "[0 1 2 3 4]"
+ a = array([True, False, True, False], dtype="?")
+ assert str(a) == "[True False True False]"
+
+ a = array(range(5), dtype="int8")
+ assert str(a) == "[0 1 2 3 4]"
+
+ a = array(range(5), dtype="int16")
+ assert str(a) == "[0 1 2 3 4]"
+
+ a = array((range(5), range(5, 10)), dtype="int16")
+ assert str(a) == "[[0 1 2 3 4]\n [5 6 7 8 9]]"
+
+ a = array(3, dtype=int)
+ assert str(a) == "3"
+
+ a = zeros((400, 400), dtype=int)
+ assert str(a) == "[[0 0 0 ..., 0 0 0]\n [0 0 0 ..., 0 0 0]\n" \
+ " [0 0 0 ..., 0 0 0]\n ..., \n [0 0 0 ..., 0 0 0]\n" \
+ " [0 0 0 ..., 0 0 0]\n [0 0 0 ..., 0 0 0]]"
+ a = zeros((2, 2, 2))
+ r = str(a)
+ assert r == '[[[0.0 0.0]\n [0.0 0.0]]\n\n [[0.0 0.0]\n [0.0 0.0]]]'
+
+ def test_str_slice(self):
+ from numpypy import array, zeros
+ a = array(range(5), float)
+ b = a[1::2]
+ assert str(b) == "[1.0 3.0]"
+ a = zeros(2002)
+ b = a[::2]
+ assert str(b) == "[0.0 0.0 0.0 ..., 0.0 0.0 0.0]"
+ a = array((range(5), range(5, 10)), dtype="int16")
+ b = a[1, 2:]
+ assert str(b) == "[7 8 9]"
+ b = a[2:1, ]
+ assert str(b) == "[]"
+
+
+class AppTestRanges(BaseNumpyAppTest):
+ def test_arange(self):
+ from numpypy import arange, array, dtype
+ a = arange(3)
+ assert (a == [0, 1, 2]).all()
+ assert a.dtype is dtype(int)
+ a = arange(3.0)
+ assert (a == [0., 1., 2.]).all()
+ assert a.dtype is dtype(float)
+ a = arange(3, 7)
+ assert (a == [3, 4, 5, 6]).all()
+ assert a.dtype is dtype(int)
+ a = arange(3, 7, 2)
+ assert (a == [3, 5]).all()
+ a = arange(3, dtype=float)
+ assert (a == [0., 1., 2.]).all()
+ assert a.dtype is dtype(float)
+ a = arange(0, 0.8, 0.1)
+ assert len(a) == 8
+ assert arange(False, True, True).dtype is dtype(int)
diff --git a/pypy/module/micronumpy/test/test_ufuncs.py b/pypy/module/micronumpy/test/test_ufuncs.py
--- a/pypy/module/micronumpy/test/test_ufuncs.py
+++ b/pypy/module/micronumpy/test/test_ufuncs.py
@@ -319,6 +319,17 @@
for v in [1.0, -1.0]:
assert arctanh(v) == math.copysign(float("inf"), v)
+ def test_sqrt(self):
+ import math
+ from numpypy import sqrt
+
+ nan, inf = float("nan"), float("inf")
+ data = [1, 2, 3, inf]
+ results = [math.sqrt(1), math.sqrt(2), math.sqrt(3), inf]
+ assert (sqrt(data) == results).all()
+ assert math.isnan(sqrt(-1))
+ assert math.isnan(sqrt(nan))
+
def test_reduce_errors(self):
from numpypy import sin, add
diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py
--- a/pypy/module/micronumpy/test/test_zjit.py
+++ b/pypy/module/micronumpy/test/test_zjit.py
@@ -1,29 +1,54 @@
+
+""" Tests that check if JIT-compiled numpy operations produce reasonably
+good assembler
+"""
+
+import py
+
+from pypy.jit.metainterp import pyjitpl
from pypy.jit.metainterp.test.support import LLJitMixin
+from pypy.jit.metainterp.warmspot import reset_stats
from pypy.module.micronumpy import interp_ufuncs, signature
-from pypy.module.micronumpy.compile import (FakeSpace,
- FloatObject, IntObject, numpy_compile, BoolObject)
-from pypy.module.micronumpy.interp_numarray import (SingleDimArray,
- SingleDimSlice)
+from pypy.module.micronumpy.compile import (numpy_compile, FakeSpace,
+ FloatObject, IntObject, BoolObject, Parser, InterpreterState)
+from pypy.module.micronumpy.interp_numarray import NDimArray, NDimSlice
from pypy.rlib.nonconst import NonConstant
from pypy.rpython.annlowlevel import llstr, hlstr
-from pypy.jit.metainterp.warmspot import reset_stats
-from pypy.jit.metainterp import pyjitpl
-
-import py
class TestNumpyJIt(LLJitMixin):
graph = None
interp = None
-
- def run(self, code):
+
+ def setup_class(cls):
+ default = """
+ a = [1,2,3,4]
+ c = a + b
+ sum(c) -> 1::1
+ a -> 3:1:2
+ """
+
+ d = {}
+ p = Parser()
+ allcodes = [p.parse(default)]
+ for name, meth in cls.__dict__.iteritems():
+ if name.startswith("define_"):
+ code = meth()
+ d[name[len("define_"):]] = len(allcodes)
+ allcodes.append(p.parse(code))
+ cls.code_mapping = d
+ cls.codes = allcodes
+
+ def run(self, name):
space = FakeSpace()
-
- def f(code):
- interp = numpy_compile(hlstr(code))
+ i = self.code_mapping[name]
+ codes = self.codes
+
+ def f(i):
+ interp = InterpreterState(codes[i])
interp.run(space)
res = interp.results[-1]
- w_res = res.eval(0).wrap(interp.space)
+ w_res = res.eval(res.start_iter()).wrap(interp.space)
if isinstance(w_res, BoolObject):
return float(w_res.boolval)
elif isinstance(w_res, FloatObject):
@@ -34,62 +59,77 @@
return -42.
if self.graph is None:
- interp, graph = self.meta_interp(f, [llstr(code)],
+ interp, graph = self.meta_interp(f, [i],
listops=True,
backendopt=True,
graph_and_interp_only=True)
self.__class__.interp = interp
self.__class__.graph = graph
-
reset_stats()
pyjitpl._warmrunnerdesc.memory_manager.alive_loops.clear()
- return self.interp.eval_graph(self.graph, [llstr(code)])
+ return self.interp.eval_graph(self.graph, [i])
- def test_add(self):
- result = self.run("""
+ def define_add():
+ return """
a = |30|
b = a + a
b -> 3
- """)
- self.check_loops({'getarrayitem_raw': 2, 'float_add': 1,
- 'setarrayitem_raw': 1, 'int_add': 1,
- 'int_lt': 1, 'guard_true': 1, 'jump': 1})
+ """
+
+ def test_add(self):
+ result = self.run("add")
+ self.check_resops({'setarrayitem_raw': 2, 'getfield_gc': 19, 'guard_class': 11,
+ 'int_add': 6, 'guard_isnull': 1, 'jump': 2, 'int_ge': 2,
+ 'getarrayitem_raw': 4, 'float_add': 2, 'guard_false': 2,
+ 'guard_value': 1})
assert result == 3 + 3
- def test_floatadd(self):
- result = self.run("""
+ def define_float_add():
+ return """
a = |30| + 3
a -> 3
- """)
+ """
+
+ def test_floatadd(self):
+ result = self.run("float_add")
assert result == 3 + 3
- self.check_loops({"getarrayitem_raw": 1, "float_add": 1,
- "setarrayitem_raw": 1, "int_add": 1,
- "int_lt": 1, "guard_true": 1, "jump": 1})
+ self.check_resops({'setarrayitem_raw': 2, 'getfield_gc': 17, 'guard_class': 11,
+ 'int_add': 4, 'guard_isnull': 1, 'jump': 2, 'int_ge': 2,
+ 'getarrayitem_raw': 2, 'float_add': 2, 'guard_false': 2,
+ 'guard_value': 1})
- def test_sum(self):
- result = self.run("""
+ def define_sum():
+ return """
a = |30|
b = a + a
sum(b)
- """)
+ """
+
+ def test_sum(self):
+ result = self.run("sum")
assert result == 2 * sum(range(30))
- self.check_loops({"getarrayitem_raw": 2, "float_add": 2,
- "int_add": 1,
- "int_lt": 1, "guard_true": 1, "jump": 1})
+ self.check_resops({'guard_class': 10, 'getfield_gc': 17, 'jump': 2,
+ 'getarrayitem_raw': 4, 'guard_value': 2, 'int_add': 4,
+ 'guard_isnull': 1, 'int_ge': 2, 'float_add': 4, 'guard_false': 2})
- def test_prod(self):
- result = self.run("""
+ def define_prod():
+ return """
a = |30|
b = a + a
prod(b)
- """)
+ """
+
+ def test_prod(self):
+ result = self.run("prod")
expected = 1
for i in range(30):
expected *= i * 2
assert result == expected
- self.check_loops({"getarrayitem_raw": 2, "float_add": 1,
- "float_mul": 1, "int_add": 1,
- "int_lt": 1, "guard_true": 1, "jump": 1})
+ self.check_resops({'guard_class': 10, 'getfield_gc': 17, 'int_add': 4,
+ 'float_mul': 2, 'guard_isnull': 1, 'jump': 2, 'int_ge': 2,
+ 'getarrayitem_raw': 4, 'float_add': 2, 'guard_false': 2,
+ 'guard_value': 2})
+
def test_max(self):
py.test.skip("broken, investigate")
@@ -113,54 +153,68 @@
min(b)
""")
assert result == -24
- self.check_loops({"getarrayitem_raw": 2, "float_add": 1,
- "float_mul": 1, "int_add": 1,
- "int_lt": 1, "guard_true": 1, "jump": 1})
+ self.check_resops({'guard_class': 10, 'getfield_gc': 15, 'guard_value': 1,
+ 'int_add': 4, 'guard_isnull': 1, 'jump': 2, 'int_ge': 2,
+ 'getarrayitem_raw': 4, 'float_add': 2, 'guard_false': 4,
+ 'float_ne': 2})
- def test_any(self):
- result = self.run("""
+ def define_any():
+ return """
a = [0,0,0,0,0,0,0,0,0,0,0]
a[8] = -12
b = a + a
any(b)
- """)
+ """
+
+ def test_any(self):
+ result = self.run("any")
assert result == 1
- self.check_loops({"getarrayitem_raw": 2, "float_add": 1,
- "float_ne": 1, "int_add": 1,
- "int_lt": 1, "guard_true": 1, "jump": 1,
- "guard_false": 1})
+ self.check_resops({'guard_class': 10, 'getfield_gc': 15, 'guard_value': 1,
+ 'int_add': 4, 'guard_isnull': 1, 'jump': 2, 'int_ge': 2,
+ 'getarrayitem_raw': 4, 'float_add': 2, 'guard_false': 4,
+ 'float_ne': 2})
- def test_already_forced(self):
- result = self.run("""
+ def define_already_forced():
+ return """
a = |30|
b = a + 4.5
b -> 5 # forces
c = b * 8
c -> 5
- """)
+ """
+
+ def test_already_forced(self):
+ result = self.run("already_forced")
assert result == (5 + 4.5) * 8
# This is the sum of the ops for both loops, however if you remove the
# optimization then you end up with 2 float_adds, so we can still be
# sure it was optimized correctly.
- self.check_loops({"getarrayitem_raw": 2, "float_mul": 1, "float_add": 1,
- "setarrayitem_raw": 2, "int_add": 2,
- "int_lt": 2, "guard_true": 2, "jump": 2})
+ self.check_resops({'setarrayitem_raw': 4, 'guard_nonnull': 1, 'getfield_gc': 35,
+ 'guard_class': 22, 'int_add': 8, 'float_mul': 2,
+ 'guard_isnull': 2, 'jump': 4, 'int_ge': 4,
+ 'getarrayitem_raw': 4, 'float_add': 2, 'guard_false': 4,
+ 'guard_value': 2})
- def test_ufunc(self):
- result = self.run("""
+
+ def define_ufunc():
+ return """
a = |30|
b = a + a
c = unegative(b)
c -> 3
- """)
+ """
+
+ def test_ufunc(self):
+ result = self.run("ufunc")
assert result == -6
- self.check_loops({"getarrayitem_raw": 2, "float_add": 1, "float_neg": 1,
- "setarrayitem_raw": 1, "int_add": 1,
- "int_lt": 1, "guard_true": 1, "jump": 1,
- })
+ self.check_resops({'setarrayitem_raw': 2, 'getfield_gc': 24, 'guard_class': 14,
+ 'int_add': 6, 'float_neg': 2, 'guard_isnull': 2, 'jump': 2,
+ 'int_ge': 2, 'getarrayitem_raw': 4, 'float_add': 2,
+ 'guard_false': 2, 'guard_value': 2})
- def test_specialization(self):
- self.run("""
+
+ def define_specialization():
+ return """
a = |30|
b = a + a
c = unegative(b)
@@ -177,49 +231,98 @@
d = a * a
unegative(d)
d -> 3
- """)
+ """
+
+ def test_specialization(self):
+ self.run("specialization")
# This is 3, not 2 because there is a bridge for the exit.
self.check_loop_count(3)
+ def define_slice():
+ return """
+ a = |30|
+ b = a -> ::3
+ c = b + b
+ c -> 3
+ """
+
+ def test_slice(self):
+ result = self.run("slice")
+ assert result == 18
+ py.test.skip("Few remaining arraylen_gc left")
+ self.check_loops({'int_mul': 2, 'getarrayitem_raw': 2, 'float_add': 1,
+ 'setarrayitem_raw': 1, 'int_add': 3,
+ 'int_lt': 1, 'guard_true': 1, 'jump': 1})
+
+ def define_multidim():
+ return """
+ a = [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]]
+ b = a + a
+ b -> 1 -> 1
+ """
+
+ def test_multidim(self):
+ result = self.run('multidim')
+ assert result == 8
+ self.check_resops({'setarrayitem_raw': 2, 'getfield_gc': 19, 'guard_class': 11,
+ 'int_add': 6, 'guard_isnull': 1, 'jump': 2, 'int_ge': 2,
+ 'getarrayitem_raw': 4, 'float_add': 2, 'guard_false': 2,
+ 'guard_value': 1})
+ # int_add might be 1 here if we try slightly harder with
+ # reusing indexes or some optimization
+
+ def define_multidim_slice():
+ return """
+ a = [[1, 2, 3, 4], [3, 4, 5, 6], [5, 6, 7, 8], [7, 8, 9, 10], [9, 10, 11, 12], [11, 12, 13, 14], [13, 14, 15, 16], [16, 17, 18, 19]]
+ b = a -> ::2
+ c = b + b
+ c -> 1 -> 1
+ """
+
+ def test_multidim_slice(self):
+ result = self.run('multidim_slice')
+ assert result == 12
+ py.test.skip("improve")
+ # XXX the bridge here is scary. Hopefully jit-targets will fix that,
+ # otherwise it looks kind of good
+ self.check_loops({})
+
+ def define_broadcast():
+ return """
+ a = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]
+ b = [1, 2, 3, 4]
+ c = a + b
+ c -> 1 -> 2
+ """
+
+ def test_broadcast(self):
+ result = self.run("broadcast")
+ assert result == 10
+ py.test.skip("improve")
+ self.check_loops({})
class TestNumpyOld(LLJitMixin):
def setup_class(cls):
+ py.test.skip("old")
from pypy.module.micronumpy.compile import FakeSpace
from pypy.module.micronumpy.interp_dtype import W_Float64Dtype
-
+
cls.space = FakeSpace()
cls.float64_dtype = cls.space.fromcache(W_Float64Dtype)
-
- def test_slice(self):
- def f(i):
- step = 3
- ar = SingleDimArray(step*i, dtype=self.float64_dtype)
- new_sig = signature.Signature.find_sig([
- SingleDimSlice.signature, ar.signature
- ])
- s = SingleDimSlice(0, step*i, step, i, ar, new_sig)
- v = interp_ufuncs.get(self.space).add.call(self.space, [s, s])
- return v.get_concrete().eval(3).val
-
- result = self.meta_interp(f, [5], listops=True, backendopt=True)
- self.check_loops({'int_mul': 1, 'getarrayitem_raw': 2, 'float_add': 1,
- 'setarrayitem_raw': 1, 'int_add': 1,
- 'int_lt': 1, 'guard_true': 1, 'jump': 1})
- assert result == f(5)
def test_slice2(self):
def f(i):
step1 = 2
step2 = 3
- ar = SingleDimArray(step2*i, dtype=self.float64_dtype)
+ ar = NDimArray(step2*i, dtype=self.float64_dtype)
new_sig = signature.Signature.find_sig([
- SingleDimSlice.signature, ar.signature
+ NDimSlice.signature, ar.signature
])
- s1 = SingleDimSlice(0, step1*i, step1, i, ar, new_sig)
+ s1 = NDimSlice(0, step1*i, step1, i, ar, new_sig)
new_sig = signature.Signature.find_sig([
- SingleDimSlice.signature, s1.signature
+ NDimSlice.signature, s1.signature
])
- s2 = SingleDimSlice(0, step2*i, step2, i, ar, new_sig)
+ s2 = NDimSlice(0, step2*i, step2, i, ar, new_sig)
v = interp_ufuncs.get(self.space).add.call(self.space, [s1, s2])
return v.get_concrete().eval(3).val
@@ -235,8 +338,8 @@
def f(i):
step = NonConstant(3)
- ar = SingleDimArray(step*i, dtype=float64_dtype)
- ar2 = SingleDimArray(i, dtype=float64_dtype)
+ ar = NDimArray(step*i, dtype=float64_dtype)
+ ar2 = NDimArray(i, dtype=float64_dtype)
ar2.get_concrete().setitem(1, float64_dtype.box(5.5))
arg = ar2.descr_add(space, ar2)
ar.setslice(space, 0, step*i, step, i, arg)
@@ -262,7 +365,7 @@
dtype = float64_dtype
else:
dtype = int32_dtype
- ar = SingleDimArray(n, dtype=dtype)
+ ar = NDimArray(n, [n], dtype=dtype)
i = 0
while i < n:
ar.get_concrete().setitem(i, int32_dtype.box(7))
diff --git a/pypy/module/pypyjit/test_pypy_c/model.py b/pypy/module/pypyjit/test_pypy_c/model.py
--- a/pypy/module/pypyjit/test_pypy_c/model.py
+++ b/pypy/module/pypyjit/test_pypy_c/model.py
@@ -271,7 +271,7 @@
thread_ticker_check = """
guard_not_invalidated?
ticker0 = getfield_raw(ticker_address, descr=<SignedFieldDescr pypysig_long_struct.c_value .*>)
- ticker1 = int_sub(ticker0, 1)
+ ticker1 = int_sub(ticker0, _)
setfield_raw(ticker_address, ticker1, descr=<SignedFieldDescr pypysig_long_struct.c_value .*>)
ticker_cond0 = int_lt(ticker1, 0)
guard_false(ticker_cond0, descr=...)
diff --git a/pypy/module/pypyjit/test_pypy_c/test_call.py b/pypy/module/pypyjit/test_pypy_c/test_call.py
--- a/pypy/module/pypyjit/test_pypy_c/test_call.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_call.py
@@ -334,26 +334,27 @@
log = self.run(main, [1000])
assert log.result == (1000, 998)
loop, = log.loops_by_filename(self.filepath)
+ # the int strategy is used here
assert loop.match_by_id('append', """
i13 = getfield_gc(p8, descr=<SignedFieldDescr list.length .*>)
i15 = int_add(i13, 1)
# Will be killed by the backend
- i17 = arraylen_gc(p7, descr=<GcPtrArrayDescr>)
- call(ConstClass(_ll_list_resize_ge), p8, i15, descr=<VoidCallDescr>)
+ p15 = getfield_gc(p8, descr=<GcPtrFieldDescr list.items .*>)
+ i17 = arraylen_gc(p15, descr=<SignedArrayDescr>)
+ call(_, p8, i15, descr=<VoidCallDescr>) # this is a call to _ll_list_resize_ge_trampoline__...
guard_no_exception(descr=...)
p17 = getfield_gc(p8, descr=<GcPtrFieldDescr list.items .*>)
- p19 = new_with_vtable(ConstClass(W_IntObject))
- setfield_gc(p19, i12, descr=<SignedFieldDescr .*W_IntObject.inst_intval .*>)
- setarrayitem_gc(p17, i13, p19, descr=<GcPtrArrayDescr>)
+ setarrayitem_gc(p17, i13, i12, descr=<SignedArrayDescr>)
""")
def test_blockstack_virtualizable(self):
def main(n):
from pypyjit import residual_call
+ l = len
i = 0
while i < n:
try:
- residual_call(len, []) # ID: call
+ residual_call(l, []) # ID: call
except:
pass
i += 1
@@ -369,11 +370,8 @@
p22 = new_with_vtable(19511408)
p24 = new_array(1, descr=<GcPtrArrayDescr>)
p26 = new_with_vtable(ConstClass(W_ListObject))
- p27 = new(descr=<SizeDescr .*>)
- p29 = new_array(0, descr=<GcPtrArrayDescr>)
setfield_gc(p0, i20, descr=<SignedFieldDescr .*PyFrame.vable_token .*>)
- setfield_gc(p27, p29, descr=<GcPtrFieldDescr list.items .*>)
- setfield_gc(p26, p27, descr=<.* .*W_ListObject.inst_wrappeditems .*>)
+ setfield_gc(p26, ConstPtr(ptr22), descr=<GcPtrFieldDescr pypy.objspace.std.listobject.W_ListObject.inst_strategy .*>)
setarrayitem_gc(p24, 0, p26, descr=<GcPtrArrayDescr>)
setfield_gc(p22, p24, descr=<GcPtrFieldDescr .*Arguments.inst_arguments_w .*>)
p32 = call_may_force(11376960, p18, p22, descr=<GcPtrCallDescr>)
@@ -486,4 +484,4 @@
i4 = int_add(i0, 1)
--TICK--
jump(..., descr=...)
- """)
\ No newline at end of file
+ """)
diff --git a/pypy/module/pypyjit/test_pypy_c/test_misc.py b/pypy/module/pypyjit/test_pypy_c/test_misc.py
--- a/pypy/module/pypyjit/test_pypy_c/test_misc.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_misc.py
@@ -201,9 +201,11 @@
assert log.result == 1000000
loop, = log.loops_by_filename(self.filepath)
assert loop.match("""
- i16 = int_ge(i12, i13)
+ i14 = getfield_gc(p12, descr=<SignedFieldDescr list.length .*>)
+ i16 = uint_ge(i12, i14)
guard_false(i16, descr=...)
- p17 = getarrayitem_gc(p15, i12, descr=<GcPtrArrayDescr>)
+ p16 = getfield_gc(p12, descr=<GcPtrFieldDescr list.items .*>)
+ p17 = getarrayitem_gc(p16, i12, descr=<GcPtrArrayDescr>)
i19 = int_add(i12, 1)
setfield_gc(p9, i19, descr=<SignedFieldDescr .*W_AbstractSeqIterObject.inst_index .*>)
guard_nonnull_class(p17, 146982464, descr=...)
@@ -217,7 +219,7 @@
i28 = int_add_ovf(i10, i25)
guard_no_overflow(descr=...)
--TICK--
- jump(p0, p1, p2, p3, p4, p5, p6, i28, i25, p9, p10, p11, i19, i13, p14, p15, descr=<Loop0>)
+ jump(p0, p1, p2, p3, p4, p5, p6, i28, i25, p9, p10, p11, p12, i19, descr=<Loop0>)
""")
@@ -337,7 +339,7 @@
a = compile('x+x+x+x+x+x', 'eval', 'eval')
b = {'x': 7}
while i < 1000:
- y = eval(a,b,b) # ID: eval
+ y = eval(a, b, b) # ID: eval
i += 1
return y
diff --git a/pypy/objspace/flow/objspace.py b/pypy/objspace/flow/objspace.py
--- a/pypy/objspace/flow/objspace.py
+++ b/pypy/objspace/flow/objspace.py
@@ -96,6 +96,12 @@
self.executioncontext.recorder = previous_recorder
self.concrete_mode -= 1
+ def is_w(self, w_one, w_two):
+ return self.is_true(self.is_(w_one, w_two))
+
+ is_ = None # real version added by add_operations()
+ id = None # real version added by add_operations()
+
def newdict(self):
if self.concrete_mode:
return Constant({})
diff --git a/pypy/objspace/flow/operation.py b/pypy/objspace/flow/operation.py
--- a/pypy/objspace/flow/operation.py
+++ b/pypy/objspace/flow/operation.py
@@ -315,7 +315,7 @@
del _add_exceptions, _add_except_ovf
def make_op(fs, name, symbol, arity, specialnames):
- if hasattr(fs, name):
+ if getattr(fs, name, None) is not None:
return
op = None
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
@@ -9,10 +9,7 @@
from pypy.rlib.debug import check_annotation
from pypy.objspace.std import stringobject
from pypy.objspace.std.intobject import W_IntObject
-from pypy.objspace.std.listobject import (
- _delitem_slice_helper, _setitem_slice_helper,
- get_positive_index
-)
+from pypy.objspace.std.listobject import get_positive_index
from pypy.objspace.std.listtype import get_list_index
from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice
from pypy.objspace.std.stringobject import W_StringObject
@@ -600,7 +597,7 @@
oldsize = len(w_bytearray.data)
start, stop, step, slicelength = w_slice.indices4(space, oldsize)
sequence2 = makebytearraydata_w(space, w_other)
- setitem_slice_helper(space, w_bytearray.data, start, step, slicelength, sequence2, empty_elem='\x00')
+ _setitem_slice_helper(space, w_bytearray.data, start, step, slicelength, sequence2, empty_elem='\x00')
def delitem__Bytearray_ANY(space, w_bytearray, w_idx):
idx = get_list_index(space, w_idx)
@@ -614,13 +611,84 @@
def delitem__Bytearray_Slice(space, w_bytearray, w_slice):
start, stop, step, slicelength = w_slice.indices4(space,
len(w_bytearray.data))
- delitem_slice_helper(space, w_bytearray.data, start, step, slicelength)
+ _delitem_slice_helper(space, w_bytearray.data, start, step, slicelength)
-# create new helper functions with different list type specialisation
-delitem_slice_helper = func_with_new_name(_delitem_slice_helper,
- 'delitem_slice_helper')
-setitem_slice_helper = func_with_new_name(_setitem_slice_helper,
- 'setitem_slice_helper')
+#XXX share the code again with the stuff in listobject.py
+def _delitem_slice_helper(space, items, start, step, slicelength):
+ if slicelength==0:
+ return
+
+ if step < 0:
+ start = start + step * (slicelength-1)
+ step = -step
+
+ if step == 1:
+ assert start >= 0
+ assert slicelength >= 0
+ del items[start:start+slicelength]
+ else:
+ n = len(items)
+ i = start
+
+ for discard in range(1, slicelength):
+ j = i+1
+ i += step
+ while j < i:
+ items[j-discard] = items[j]
+ j += 1
+
+ j = i+1
+ while j < n:
+ items[j-slicelength] = items[j]
+ j += 1
+ start = n - slicelength
+ assert start >= 0 # annotator hint
+ del items[start:]
+
+def _setitem_slice_helper(space, items, start, step, slicelength, sequence2,
+ empty_elem):
+ assert slicelength >= 0
+ oldsize = len(items)
+ len2 = len(sequence2)
+ if step == 1: # Support list resizing for non-extended slices
+ delta = slicelength - len2
+ if delta < 0:
+ delta = -delta
+ newsize = oldsize + delta
+ # XXX support this in rlist!
+ items += [empty_elem] * delta
+ lim = start+len2
+ i = newsize - 1
+ while i >= lim:
+ items[i] = items[i-delta]
+ i -= 1
+ elif start >= 0:
+ del items[start:start+delta]
+ else:
+ assert delta==0 # start<0 is only possible with slicelength==0
+ elif len2 != slicelength: # No resize for extended slices
+ raise operationerrfmt(space.w_ValueError, "attempt to "
+ "assign sequence of size %d to extended slice of size %d",
+ len2, slicelength)
+
+ if sequence2 is items:
+ if step > 0:
+ # Always copy starting from the right to avoid
+ # having to make a shallow copy in the case where
+ # the source and destination lists are the same list.
+ i = len2 - 1
+ start += i*step
+ while i >= 0:
+ items[start] = sequence2[i]
+ start -= step
+ i -= 1
+ return
+ else:
+ # Make a shallow copy to more easily handle the reversal case
+ sequence2 = list(sequence2)
+ for i in range(len2):
+ items[start] = sequence2[i]
+ start += step
def _strip(space, w_bytearray, u_chars, left, right):
# note: mostly copied from stringobject._strip
diff --git a/pypy/objspace/std/celldict.py b/pypy/objspace/std/celldict.py
--- a/pypy/objspace/std/celldict.py
+++ b/pypy/objspace/std/celldict.py
@@ -65,11 +65,11 @@
if isinstance(cell, ModuleCell):
cell.w_value = w_value
return
- # If the new value and the current value are the same, don't create a
- # level of indirection, or mutate are version.
- if self.space.is_w(w_value, cell):
- return
if cell is not None:
+ # If the new value and the current value are the same, don't create a
+ # level of indirection, or mutate the version.
+ if self.space.is_w(w_value, cell):
+ return
w_value = ModuleCell(w_value)
self.mutated()
self.unerase(w_dict.dstorage)[key] = w_value
diff --git a/pypy/objspace/std/complexobject.py b/pypy/objspace/std/complexobject.py
--- a/pypy/objspace/std/complexobject.py
+++ b/pypy/objspace/std/complexobject.py
@@ -5,12 +5,46 @@
from pypy.objspace.std.register_all import register_all
from pypy.objspace.std.floatobject import W_FloatObject, _hash_float
from pypy.objspace.std.longobject import W_LongObject
+from pypy.rlib.rbigint import rbigint
from pypy.rlib.rfloat import (
formatd, DTSF_STR_PRECISION, isinf, isnan, copysign)
import math
-class W_ComplexObject(W_Object):
+
+class W_AbstractComplexObject(W_Object):
+ __slots__ = ()
+
+ def is_w(self, space, w_other):
+ from pypy.rlib.longlong2float import float2longlong
+ if not isinstance(w_other, W_AbstractComplexObject):
+ return False
+ if self.user_overridden_class or w_other.user_overridden_class:
+ return self is w_other
+ real1 = space.float_w(space.getattr(self, space.wrap("real")))
+ real2 = space.float_w(space.getattr(w_other, space.wrap("real")))
+ imag1 = space.float_w(space.getattr(self, space.wrap("imag")))
+ imag2 = space.float_w(space.getattr(w_other, space.wrap("imag")))
+ real1 = float2longlong(real1)
+ real2 = float2longlong(real2)
+ imag1 = float2longlong(imag1)
+ imag2 = float2longlong(imag2)
+ return real1 == real2 and imag1 == imag2
+
+ def unique_id(self, space):
+ if self.user_overridden_class:
+ return W_Object.unique_id(self, space)
+ from pypy.rlib.longlong2float import float2longlong
+ from pypy.objspace.std.model import IDTAG_COMPLEX as tag
+ real = space.float_w(space.getattr(self, space.wrap("real")))
+ imag = space.float_w(space.getattr(self, space.wrap("imag")))
+ real_b = rbigint.fromrarith_int(float2longlong(real))
+ imag_b = rbigint.fromrarith_int(float2longlong(imag))
+ val = real_b.lshift(64).or_(imag_b).lshift(3).or_(rbigint.fromint(tag))
+ return space.newlong_from_rbigint(val)
+
+
+class W_ComplexObject(W_AbstractComplexObject):
"""This is a reimplementation of the CPython "PyComplexObject"
"""
from pypy.objspace.std.complextype import complex_typedef as typedef
diff --git a/pypy/objspace/std/floatobject.py b/pypy/objspace/std/floatobject.py
--- a/pypy/objspace/std/floatobject.py
+++ b/pypy/objspace/std/floatobject.py
@@ -21,10 +21,33 @@
import math
from pypy.objspace.std.intobject import W_IntObject
-class W_FloatObject(W_Object):
- """This is a reimplementation of the CPython "PyFloatObject"
- it is assumed that the constructor takes a real Python float as
- an argument"""
+class W_AbstractFloatObject(W_Object):
+ __slots__ = ()
+
+ def is_w(self, space, w_other):
+ from pypy.rlib.longlong2float import float2longlong
+ if not isinstance(w_other, W_AbstractFloatObject):
+ return False
+ if self.user_overridden_class or w_other.user_overridden_class:
+ return self is w_other
+ one = float2longlong(space.float_w(self))
+ two = float2longlong(space.float_w(w_other))
+ return one == two
+
+ def unique_id(self, space):
+ if self.user_overridden_class:
+ return W_Object.unique_id(self, space)
+ from pypy.rlib.longlong2float import float2longlong
+ from pypy.objspace.std.model import IDTAG_FLOAT as tag
+ val = float2longlong(space.float_w(self))
+ b = rbigint.fromrarith_int(val)
+ b = b.lshift(3).or_(rbigint.fromint(tag))
+ return space.newlong_from_rbigint(b)
+
+
+class W_FloatObject(W_AbstractFloatObject):
+ """This is a implementation of the app-level 'float' type.
+ The constructor takes an RPython float as an argument."""
from pypy.objspace.std.floattype import float_typedef as typedef
_immutable_fields_ = ['floatval']
diff --git a/pypy/objspace/std/frame.py b/pypy/objspace/std/frame.py
--- a/pypy/objspace/std/frame.py
+++ b/pypy/objspace/std/frame.py
@@ -3,13 +3,11 @@
import operator
from pypy.rlib.unroll import unrolling_iterable
-from pypy.interpreter import pyopcode, function
+from pypy.interpreter import pyopcode
from pypy.interpreter.pyframe import PyFrame
-from pypy.interpreter.error import OperationError, operationerrfmt
-from pypy.module.__builtin__ import Module
+from pypy.interpreter.error import OperationError
from pypy.objspace.std import intobject, smallintobject
from pypy.objspace.std.multimethod import FailedToImplement
-from pypy.objspace.std.dictmultiobject import W_DictMultiObject
from pypy.objspace.std.listobject import W_ListObject
@@ -58,7 +56,7 @@
w_1 = f.popvalue()
if type(w_1) is W_ListObject and type(w_2) is intobject.W_IntObject:
try:
- w_result = w_1.wrappeditems[w_2.intval]
+ w_result = w_1.getitem(w_2.intval)
except IndexError:
raise OperationError(f.space.w_IndexError,
f.space.wrap("list index out of range"))
diff --git a/pypy/objspace/std/intobject.py b/pypy/objspace/std/intobject.py
--- a/pypy/objspace/std/intobject.py
+++ b/pypy/objspace/std/intobject.py
@@ -19,6 +19,22 @@
class W_AbstractIntObject(W_Object):
__slots__ = ()
+ def is_w(self, space, w_other):
+ if not isinstance(w_other, W_AbstractIntObject):
+ return False
+ if self.user_overridden_class or w_other.user_overridden_class:
+ return self is w_other
+ return space.int_w(self) == space.int_w(w_other)
+
+ def unique_id(self, space):
+ if self.user_overridden_class:
+ return W_Object.unique_id(self, space)
+ from pypy.objspace.std.model import IDTAG_INT as tag
+ b = space.bigint_w(self)
+ b = b.lshift(3).or_(rbigint.fromint(tag))
+ return space.newlong_from_rbigint(b)
+
+
class W_IntObject(W_AbstractIntObject):
__slots__ = 'intval'
_immutable_fields_ = ['intval']
diff --git a/pypy/objspace/std/iterobject.py b/pypy/objspace/std/iterobject.py
--- a/pypy/objspace/std/iterobject.py
+++ b/pypy/objspace/std/iterobject.py
@@ -33,9 +33,9 @@
"""Sequence iterator specialized for lists, accessing
directly their RPython-level list of wrapped objects.
"""
- def __init__(w_self, w_seq, wrappeditems):
+ def __init__(w_self, w_seq):
W_AbstractSeqIterObject.__init__(w_self, w_seq)
- w_self.listitems = wrappeditems
+ w_self.w_seq = w_seq
class W_FastTupleIterObject(W_AbstractSeqIterObject):
"""Sequence iterator specialized for tuples, accessing
@@ -105,13 +105,15 @@
return w_seqiter
def next__FastListIter(space, w_seqiter):
- if w_seqiter.listitems is None:
+ from pypy.objspace.std.listobject import W_ListObject
+ w_seq = w_seqiter.w_seq
+ if w_seq is None:
raise OperationError(space.w_StopIteration, space.w_None)
+ assert isinstance(w_seq, W_ListObject)
index = w_seqiter.index
try:
- w_item = w_seqiter.listitems[index]
+ w_item = w_seq.getitem(index)
except IndexError:
- w_seqiter.listitems = None
w_seqiter.w_seq = None
raise OperationError(space.w_StopIteration, space.w_None)
w_seqiter.index = index + 1
diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py
--- a/pypy/objspace/std/listobject.py
+++ b/pypy/objspace/std/listobject.py
@@ -5,35 +5,937 @@
from pypy.objspace.std.inttype import wrapint
from pypy.objspace.std.listtype import get_list_index
from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice
-
from pypy.objspace.std import slicetype
from pypy.interpreter import gateway, baseobjspace
+from pypy.rlib.objectmodel import instantiate, specialize
from pypy.rlib.listsort import make_timsort_class
+from pypy.rlib import rerased, jit
from pypy.interpreter.argument import Signature
+UNROLL_CUTOFF = 5
+
class W_AbstractListObject(W_Object):
__slots__ = ()
+def make_range_list(space, start, step, length):
+ if length <= 0:
+ strategy = space.fromcache(EmptyListStrategy)
+ storage = strategy.erase(None)
+ else:
+ strategy = space.fromcache(RangeListStrategy)
+ storage = strategy.erase((start, step, length))
+ return W_ListObject.from_storage_and_strategy(space, storage, strategy)
+
+def make_empty_list(space):
+ strategy = space.fromcache(EmptyListStrategy)
+ storage = strategy.erase(None)
+ return W_ListObject.from_storage_and_strategy(space, storage, strategy)
+
+ at jit.look_inside_iff(lambda space, list_w: jit.isconstant(len(list_w)) and len(list_w) < UNROLL_CUTOFF)
+def get_strategy_from_list_objects(space, list_w):
+ if not list_w:
+ return space.fromcache(EmptyListStrategy)
+
+ # check for ints
+ for w_obj in list_w:
+ if not is_W_IntObject(w_obj):
+ break
+ else:
+ return space.fromcache(IntegerListStrategy)
+
+ # check for strings
+ for w_obj in list_w:
+ if not is_W_StringObject(w_obj):
+ break
+ else:
+ return space.fromcache(StringListStrategy)
+
+ return space.fromcache(ObjectListStrategy)
+
+def is_W_IntObject(w_object):
+ from pypy.objspace.std.intobject import W_IntObject
+ return type(w_object) is W_IntObject
+
+def is_W_StringObject(w_object):
+ from pypy.objspace.std.stringobject import W_StringObject
+ return type(w_object) is W_StringObject
+
+
+
class W_ListObject(W_AbstractListObject):
from pypy.objspace.std.listtype import list_typedef as typedef
- def __init__(w_self, wrappeditems):
- w_self.wrappeditems = wrappeditems
+ def __init__(w_self, space, wrappeditems):
+ assert isinstance(wrappeditems, list)
+ w_self.space = space
+ if space.config.objspace.std.withliststrategies:
+ w_self.strategy = get_strategy_from_list_objects(space, wrappeditems)
+ else:
+ w_self.strategy = space.fromcache(ObjectListStrategy)
+ w_self.init_from_list_w(wrappeditems)
+
+ @staticmethod
+ def from_storage_and_strategy(space, storage, strategy):
+ w_self = instantiate(W_ListObject)
+ w_self.space = space
+ w_self.strategy = strategy
+ w_self.lstorage = storage
+ if not space.config.objspace.std.withliststrategies:
+ w_self.switch_to_object_strategy()
+ return w_self
+
+ @staticmethod
+ def newlist_str(space, list_s):
+ strategy = space.fromcache(StringListStrategy)
+ storage = strategy.erase(list_s)
+ return W_ListObject.from_storage_and_strategy(space, storage, strategy)
def __repr__(w_self):
""" representation for debugging purposes """
- return "%s(%s)" % (w_self.__class__.__name__, w_self.wrappeditems)
+ return "%s(%s, %s)" % (w_self.__class__.__name__, w_self.strategy, w_self.lstorage._x)
def unwrap(w_list, space):
- items = [space.unwrap(w_item) for w_item in w_list.wrappeditems]# XXX generic mixed types unwrap
+ # for tests only!
+ items = [space.unwrap(w_item) for w_item in w_list.getitems()]
return list(items)
+ def switch_to_object_strategy(self):
+ list_w = self.getitems()
+ self.strategy = self.space.fromcache(ObjectListStrategy)
+ # XXX this is quite indirect
+ self.init_from_list_w(list_w)
+
+ def _temporarily_as_objects(self):
+ if self.strategy is self.space.fromcache(ObjectListStrategy):
+ return self
+ list_w = self.getitems()
+ strategy = self.space.fromcache(ObjectListStrategy)
+ storage = strategy.erase(list_w)
+ w_objectlist = W_ListObject.from_storage_and_strategy(self.space, storage, strategy)
+ return w_objectlist
+
+ # ___________________________________________________
+
+ def init_from_list_w(self, list_w):
+ """Initializes listobject by iterating through the given list of
+ wrapped items, unwrapping them if neccessary and creating a
+ new erased object as storage"""
+ self.strategy.init_from_list_w(self, list_w)
+
+ def clone(self):
+ """Returns a clone by creating a new listobject
+ with the same strategy and a copy of the storage"""
+ return self.strategy.clone(self)
+
+ def copy_into(self, other):
+ """Used only when extending an EmptyList. Sets the EmptyLists
+ strategy and storage according to the other W_List"""
+ self.strategy.copy_into(self, other)
+
+ def contains(self, w_obj):
+ """Returns unwrapped boolean, saying wether w_obj exists
+ in the list."""
+ return self.strategy.contains(self, w_obj)
+
def append(w_list, w_item):
- w_list.wrappeditems.append(w_item)
+ """Appends the wrapped item to the end of the list."""
+ w_list.strategy.append(w_list, w_item)
+
+ def length(self):
+ return self.strategy.length(self)
+
+ def getitem(self, index):
+ """Returns the wrapped object that is found in the
+ list at the given index. The index must be unwrapped.
+ May raise IndexError."""
+ return self.strategy.getitem(self, index)
+
+ def getslice(self, start, stop, step, length):
+ """Returns a slice of the list defined by the arguments. Arguments must be
+ normalized (i.e. using normalize_simple_slice or W_Slice.indices4).
+ May raise IndexError."""
+ return self.strategy.getslice(self, start, stop, step, length)
+
+ def getitems(self):
+ """Returns a list of all items after wrapping them. The result can
+ share with the storage, if possible."""
+ return self.strategy.getitems(self)
+
+ def getitems_copy(self):
+ """Returns a copy of all items in the list. Same as getitems except for
+ ObjectListStrategy."""
+ return self.strategy.getitems_copy(self)
+
+ def getitems_str(self):
+ """ Return the items in the list as unwrapped strings. If the list does
+ not use the list strategy, return None. """
+ return self.strategy.getitems_str(self)
+ # ___________________________________________________
+
+
+ def mul(self, times):
+ """Returns a copy of the list, multiplied by times.
+ Argument must be unwrapped."""
+ return self.strategy.mul(self, times)
+
+ def inplace_mul(self, times):
+ """Alters the list by multiplying its content by times."""
+ self.strategy.inplace_mul(self, times)
+
+ def deleteslice(self, start, step, length):
+ """Deletes a slice from the list. Used in delitem and delslice.
+ Arguments must be normalized (see getslice)."""
+ self.strategy.deleteslice(self, start, step, length)
+
+ def pop(self, index):
+ """Pops an item from the list. Index must be normalized.
+ May raise IndexError."""
+ return self.strategy.pop(self, index)
+
+ def pop_end(self):
+ """ Pop the last element from the list."""
+ return self.strategy.pop_end(self)
+
+ def setitem(self, index, w_item):
+ """Inserts a wrapped item at the given (unwrapped) index.
+ May raise IndexError."""
+ self.strategy.setitem(self, index, w_item)
+
+ def setslice(self, start, step, slicelength, sequence_w):
+ """Sets the slice of the list from start to start+step*slicelength to
+ the sequence sequence_w.
+ Used by setslice and setitem."""
+ self.strategy.setslice(self, start, step, slicelength, sequence_w)
+
+ def insert(self, index, w_item):
+ """Inserts an item at the given position. Item must be wrapped,
+ index not."""
+ self.strategy.insert(self, index, w_item)
+
+ def extend(self, items_w):
+ """Appends the given list of wrapped items."""
+ self.strategy.extend(self, items_w)
+
+ def reverse(self):
+ """Reverses the list."""
+ self.strategy.reverse(self)
+
+ def sort(self, reverse):
+ """Sorts the list ascending or descending depending on
+ argument reverse. Argument must be unwrapped."""
+ self.strategy.sort(self, reverse)
registerimplementation(W_ListObject)
+class ListStrategy(object):
+
+ def __init__(self, space):
+ self.space = space
+
+ def init_from_list_w(self, w_list, list_w):
+ raise NotImplementedError
+
+ def clone(self, w_list):
+ raise NotImplementedError
+
+ def copy_into(self, w_list, w_other):
+ raise NotImplementedError
+
+ def contains(self, w_list, w_obj):
+ # needs to be safe against eq_w() mutating the w_list behind our back
+ i = 0
+ while i < w_list.length(): # intentionally always calling len!
+ if self.space.eq_w(w_list.getitem(i), w_obj):
+ return True
+ i += 1
+ return False
+
+ def length(self, w_list):
+ raise NotImplementedError
+
+ def getitem(self, w_list, index):
+ raise NotImplementedError
+
+ def getslice(self, w_list, start, stop, step, length):
+ raise NotImplementedError
+
+ def getitems(self, w_list):
+ return self.getitems_copy(w_list)
+
+ def getitems_copy(self, w_list):
+ raise NotImplementedError
+
+ def getitems_str(self, w_list):
+ return None
+
+ def getstorage_copy(self, w_list):
+ raise NotImplementedError
+
+ def append(self, w_list, w_item):
+ raise NotImplementedError
+
+ def mul(self, w_list, times):
+ w_newlist = w_list.clone()
+ w_newlist.inplace_mul(times)
+ return w_newlist
+
+ def inplace_mul(self, w_list, times):
+ raise NotImplementedError
+
+ def deleteslice(self, w_list, start, step, slicelength):
+ raise NotImplementedError
+
+ def pop(self, w_list, index):
+ raise NotImplementedError
+
+ def pop_end(self, w_list):
+ return self.pop(w_list, self.length(w_list) - 1)
+
+ def setitem(self, w_list, index, w_item):
+ raise NotImplementedError
+
+ def setslice(self, w_list, start, step, slicelength, sequence_w):
+ raise NotImplementedError
+
+ def insert(self, w_list, index, w_item):
+ raise NotImplementedError
+
+ def extend(self, w_list, items_w):
+ raise NotImplementedError
+
+ def reverse(self, w_list):
+ raise NotImplementedError
+
+ def sort(self, w_list, reverse):
+ raise NotImplementedError
+
+class EmptyListStrategy(ListStrategy):
+ """EmptyListStrategy is used when a W_List withouth elements is created.
+ The storage is None. When items are added to the W_List a new RPython list
+ is created and the strategy and storage of the W_List are changed depending
+ to the added item.
+ W_Lists do not switch back to EmptyListStrategy when becoming empty again."""
+
+ def __init__(self, space):
+ ListStrategy.__init__(self, space)
+ # cache an empty list that is used whenever getitems is called (i.e. sorting)
+ self.cached_emptylist_w = []
+
+ def init_from_list_w(self, w_list, list_w):
+ assert len(list_w) == 0
+ w_list.lstorage = self.erase(None)
+
+ erase, unerase = rerased.new_erasing_pair("empty")
+ erase = staticmethod(erase)
+ unerase = staticmethod(unerase)
+
+ def clone(self, w_list):
+ return W_ListObject.from_storage_and_strategy(self.space, w_list.lstorage, self)
+
+ def copy_into(self, w_list, w_other):
+ pass
+
+ def contains(self, w_list, w_obj):
+ return False
+
+ def length(self, w_list):
+ return 0
+
+ def getitem(self, w_list, index):
+ raise IndexError
+
+ def getslice(self, w_list, start, stop, step, length):
+ # will never be called because the empty list case is already caught in
+ # getslice__List_ANY_ANY and getitem__List_Slice
+ return W_ListObject(self.space, self.cached_emptylist_w)
+
+ def getitems(self, w_list):
+ return self.cached_emptylist_w
+
+ def getitems_copy(self, w_list):
+ return []
+
+ def getstorage_copy(self, w_list):
+ return self.erase(None)
+
+ def switch_to_correct_strategy(self, w_list, w_item):
+ if is_W_IntObject(w_item):
+ strategy = self.space.fromcache(IntegerListStrategy)
+ elif is_W_StringObject(w_item):
+ strategy = self.space.fromcache(StringListStrategy)
+ else:
+ strategy = self.space.fromcache(ObjectListStrategy)
+
+ storage = strategy.get_empty_storage()
+ w_list.strategy = strategy
+ w_list.lstorage = storage
+
+ def append(self, w_list, w_item):
+ self.switch_to_correct_strategy(w_list, w_item)
+ w_list.append(w_item)
+
+ def inplace_mul(self, w_list, times):
+ return
+
+ def deleteslice(self, w_list, start, step, slicelength):
+ pass
+
+ def pop(self, w_list, index):
+ # will not be called because IndexError was already raised in
+ # list_pop__List_ANY
+ raise IndexError
+
+ def setitem(self, w_list, index, w_item):
+ raise IndexError
+
+ def setslice(self, w_list, start, step, slicelength, w_other):
+ strategy = w_other.strategy
+ storage = strategy.getstorage_copy(w_other)
+ w_list.strategy = strategy
+ w_list.lstorage = storage
+
+ def sort(self, w_list, reverse):
+ return
+
+ def insert(self, w_list, index, w_item):
+ assert index == 0
+ self.append(w_list, w_item)
+
+ def extend(self, w_list, w_other):
+ w_other.copy_into(w_list)
+
+ def reverse(self, w_list):
+ pass
+
+class RangeListStrategy(ListStrategy):
+ """RangeListStrategy is used when a list is created using the range method.
+ The storage is a tuple containing only three integers start, step and length
+ and elements are calculated based on these values.
+ On any operation destroying the range (inserting, appending non-ints)
+ the strategy is switched to IntegerListStrategy."""
+
+ def switch_to_integer_strategy(self, w_list):
+ items = self._getitems_range(w_list, False)
+ strategy = w_list.strategy = self.space.fromcache(IntegerListStrategy)
+ w_list.lstorage = strategy.erase(items)
+
+ def wrap(self, intval):
+ return self.space.wrap(intval)
+
+ def unwrap(self, w_int):
+ return self.space.int_w(w_int)
+
+ def init_from_list_w(self, w_list, list_w):
+ raise NotImplementedError
+
+ erase, unerase = rerased.new_erasing_pair("range")
+ erase = staticmethod(erase)
+ unerase = staticmethod(unerase)
+
+ def clone(self, w_list):
+ storage = w_list.lstorage # lstorage is tuple, no need to clone
+ w_clone = W_ListObject.from_storage_and_strategy(self.space, storage, self)
+ return w_clone
+
+ def copy_into(self, w_list, w_other):
+ w_other.strategy = self
+ w_other.lstorage = w_list.lstorage
+
+ def contains(self, w_list, w_obj):
+ if is_W_IntObject(w_obj):
+ start, step, length = self.unerase(w_list.lstorage)
+ obj = self.unwrap(w_obj)
+ i = start
+ if step > 0 and start <= obj <= start + (length - 1) * step and (start - obj) % step == 0:
+ return True
+ elif step < 0 and start + (length -1) * step <= obj <= start and (start - obj) % step == 0:
+ return True
+ else:
+ return False
+ return ListStrategy.contains(self, w_list, w_obj)
+
+ def length(self, w_list):
+ return self.unerase(w_list.lstorage)[2]
+
+ def _getitem_unwrapped(self, w_list, i):
+ v = self.unerase(w_list.lstorage)
+ start = v[0]
+ step = v[1]
+ length = v[2]
+ if i < 0:
+ i += length
+ if i < 0:
+ raise IndexError
+ elif i >= length:
+ raise IndexError
+ return start + i * step
+
+ def getitem(self, w_list, i):
+ return self.wrap(self._getitem_unwrapped(w_list, i))
+
+ def getitems_copy(self, w_list):
+ return self._getitems_range(w_list, True)
+
+ def getstorage_copy(self, w_list):
+ # tuple is unmutable
+ return w_list.lstorage
+
+
+ @specialize.arg(2)
+ def _getitems_range(self, w_list, wrap_items):
+ l = self.unerase(w_list.lstorage)
+ start = l[0]
+ step = l[1]
+ length = l[2]
+ if wrap_items:
+ r = [None] * length
+ else:
+ r = [0] * length
+ i = start
+ n = 0
+ while n < length:
+ if wrap_items:
+ r[n] = self.wrap(i)
+ else:
+ r[n] = i
+ i += step
+ n += 1
+
+ return r
+
+ def getslice(self, w_list, start, stop, step, length):
+ v = self.unerase(w_list.lstorage)
+ old_start = v[0]
+ old_step = v[1]
+ old_length = v[2]
+
+ new_start = self._getitem_unwrapped(w_list, start)
+ new_step = old_step * step
+ return make_range_list(self.space, new_start, new_step, length)
+
+ def append(self, w_list, w_item):
+ if is_W_IntObject(w_item):
+ l = self.unerase(w_list.lstorage)
+ step = l[1]
+ last_in_range = self._getitem_unwrapped(w_list, -1)
+ if self.unwrap(w_item) - step == last_in_range:
+ new = self.erase((l[0],l[1],l[2]+1))
+ w_list.lstorage = new
+ return
+
+ self.switch_to_integer_strategy(w_list)
+ else:
+ w_list.switch_to_object_strategy()
+ w_list.append(w_item)
+
+ def inplace_mul(self, w_list, times):
+ self.switch_to_integer_strategy(w_list)
+ w_list.inplace_mul(times)
+
+ def deleteslice(self, w_list, start, step, slicelength):
+ self.switch_to_integer_strategy(w_list)
+ w_list.deleteslice(start, step, slicelength)
+
+ def pop_end(self, w_list):
+ start, step, length = self.unerase(w_list.lstorage)
+ w_result = self.wrap(start + (length - 1) * step)
+ new = self.erase((start, step, length - 1))
+ w_list.lstorage = new
+ return w_result
+
+ def pop(self, w_list, index):
+ l = self.unerase(w_list.lstorage)
+ start = l[0]
+ step = l[1]
+ length = l[2]
+ if index == 0:
+ w_result = self.wrap(start)
+ new = self.erase((start + step, step, length - 1))
+ w_list.lstorage = new
+ return w_result
+ elif index == length - 1:
+ return self.pop_end(w_list)
+ else:
+ self.switch_to_integer_strategy(w_list)
+ return w_list.pop(index)
+
+ def setitem(self, w_list, index, w_item):
+ self.switch_to_integer_strategy(w_list)
+ w_list.setitem(index, w_item)
+
+ def setslice(self, w_list, start, step, slicelength, sequence_w):
+ self.switch_to_integer_strategy(w_list)
+ w_list.setslice(start, step, slicelength, sequence_w)
+
+ def sort(self, w_list, reverse):
+ start, step, length = self.unerase(w_list.lstorage)
+ if step > 0 and reverse or step < 0 and not reverse:
+ start = start + step * (length - 1)
+ step = step * (-1)
+ else:
+ return
+ w_list.lstorage = self.erase((start, step, length))
+
+ def insert(self, w_list, index, w_item):
+ self.switch_to_integer_strategy(w_list)
+ w_list.insert(index, w_item)
+
+ def extend(self, w_list, items_w):
+ self.switch_to_integer_strategy(w_list)
+ w_list.extend(items_w)
+
+ def reverse(self, w_list):
+ v = self.unerase(w_list.lstorage)
+ last = self._getitem_unwrapped(w_list, -1)
+ length = v[2]
+ skip = v[1]
+ new = self.erase((last, -skip, length))
+ w_list.lstorage = new
+
+class AbstractUnwrappedStrategy(object):
+ _mixin_ = True
+
+ def wrap(self, unwrapped):
+ raise NotImplementedError
+
+ def unwrap(self, wrapped):
+ raise NotImplementedError
+
+ @staticmethod
+ def unerase(storage):
+ raise NotImplementedError("abstract base class")
+
+ @staticmethod
+ def erase(obj):
+ raise NotImplementedError("abstract base class")
+
+ def is_correct_type(self, w_obj):
+ raise NotImplementedError("abstract base class")
+
+ def list_is_correct_type(self, w_list):
+ raise NotImplementedError("abstract base class")
+
+ @jit.look_inside_iff(lambda space, w_list, list_w:
+ jit.isconstant(len(list_w)) and len(list_w) < UNROLL_CUTOFF)
+ def init_from_list_w(self, w_list, list_w):
+ l = [self.unwrap(w_item) for w_item in list_w]
+ w_list.lstorage = self.erase(l)
+
+ def get_empty_storage(self):
+ return self.erase([])
+
+ def clone(self, w_list):
+ l = self.unerase(w_list.lstorage)
+ storage = self.erase(l[:])
+ w_clone = W_ListObject.from_storage_and_strategy(self.space, storage, self)
+ return w_clone
+
+ def copy_into(self, w_list, w_other):
+ w_other.strategy = self
+ items = self.unerase(w_list.lstorage)[:]
+ w_other.lstorage = self.erase(items)
+
+ def contains(self, w_list, w_obj):
+ if self.is_correct_type(w_obj):
+ obj = self.unwrap(w_obj)
+ l = self.unerase(w_list.lstorage)
+ for i in l:
+ if i == obj:
+ return True
+ return ListStrategy.contains(self, w_list, w_obj)
+
+ def length(self, w_list):
+ return len(self.unerase(w_list.lstorage))
+
+ def getitem(self, w_list, index):
+ l = self.unerase(w_list.lstorage)
+ try:
+ r = l[index]
+ except IndexError: # make RPython raise the exception
+ raise
+ return self.wrap(r)
+
+ @jit.look_inside_iff(lambda self, w_list:
+ jit.isconstant(w_list.length()) and w_list.length() < UNROLL_CUTOFF)
+ def getitems_copy(self, w_list):
+ return [self.wrap(item) for item in self.unerase(w_list.lstorage)]
+
+ def getstorage_copy(self, w_list):
+ items = self.unerase(w_list.lstorage)[:]
+ return self.erase(items)
+
+
+ def getslice(self, w_list, start, stop, step, length):
+ if step == 1 and 0 <= start <= stop:
+ l = self.unerase(w_list.lstorage)
+ assert start >= 0
+ assert stop >= 0
+ sublist = l[start:stop]
+ storage = self.erase(sublist)
+ return W_ListObject.from_storage_and_strategy(self.space, storage, self)
+ else:
+ subitems_w = [self._none_value] * length
+ l = self.unerase(w_list.lstorage)
+ for i in range(length):
+ try:
+ subitems_w[i] = l[start]
+ start += step
+ except IndexError:
+ raise
+ storage = self.erase(subitems_w)
+ return W_ListObject.from_storage_and_strategy(self.space, storage, self)
+
+ def append(self, w_list, w_item):
+
+ if self.is_correct_type(w_item):
+ self.unerase(w_list.lstorage).append(self.unwrap(w_item))
+ return
+
+ w_list.switch_to_object_strategy()
+ w_list.append(w_item)
+
+ def insert(self, w_list, index, w_item):
+ l = self.unerase(w_list.lstorage)
+
+ if self.is_correct_type(w_item):
+ l.insert(index, self.unwrap(w_item))
+ return
+
+ w_list.switch_to_object_strategy()
+ w_list.insert(index, w_item)
+
+ def extend(self, w_list, w_other):
+ l = self.unerase(w_list.lstorage)
+ if self.list_is_correct_type(w_other):
+ l += self.unerase(w_other.lstorage)
+ return
+ elif w_other.strategy is self.space.fromcache(EmptyListStrategy):
+ return
+
+ w_other = w_other._temporarily_as_objects()
+ w_list.switch_to_object_strategy()
+ w_list.extend(w_other)
+
+ def setitem(self, w_list, index, w_item):
+ l = self.unerase(w_list.lstorage)
+
+ if self.is_correct_type(w_item):
+ try:
+ l[index] = self.unwrap(w_item)
+ except IndexError:
+ raise
+ return
+
+ w_list.switch_to_object_strategy()
+ w_list.setitem(index, w_item)
+
+ def setslice(self, w_list, start, step, slicelength, w_other):
+ assert slicelength >= 0
+ items = self.unerase(w_list.lstorage)
+
+ if self is self.space.fromcache(ObjectListStrategy):
+ w_other = w_other._temporarily_as_objects()
+ elif (not self.list_is_correct_type(w_other) and
+ w_other.length() != 0):
+ w_list.switch_to_object_strategy()
+ w_other_as_object = w_other._temporarily_as_objects()
+ assert w_other_as_object.strategy is self.space.fromcache(ObjectListStrategy)
+ w_list.setslice(start, step, slicelength, w_other_as_object)
+ return
+
+ oldsize = len(items)
+ len2 = w_other.length()
+ if step == 1: # Support list resizing for non-extended slices
+ delta = slicelength - len2
+ if delta < 0:
+ delta = -delta
+ newsize = oldsize + delta
+ # XXX support this in rlist!
+ items += [self._none_value] * delta
+ lim = start+len2
+ i = newsize - 1
+ while i >= lim:
+ items[i] = items[i-delta]
+ i -= 1
+ elif start >= 0:
+ del items[start:start+delta]
+ else:
+ assert delta==0 # start<0 is only possible with slicelength==0
+ elif len2 != slicelength: # No resize for extended slices
+ raise operationerrfmt(self.space.w_ValueError, "attempt to "
+ "assign sequence of size %d to extended slice of size %d",
+ len2, slicelength)
+
+ if w_other.strategy is self.space.fromcache(EmptyListStrategy):
+ other_items = []
+ else:
+ # at this point both w_list and w_other have the same type, so
+ # self.unerase is valid for both of them
+ other_items = self.unerase(w_other.lstorage)
+ if other_items is items:
+ if step > 0:
+ # Always copy starting from the right to avoid
+ # having to make a shallow copy in the case where
+ # the source and destination lists are the same list.
+ i = len2 - 1
+ start += i*step
+ while i >= 0:
+ items[start] = other_items[i]
+ start -= step
+ i -= 1
+ return
+ else:
+ # Make a shallow copy to more easily handle the reversal case
+ w_list.reverse()
+ return
+ #other_items = list(other_items)
+ for i in range(len2):
+ items[start] = other_items[i]
+ start += step
+
+ def deleteslice(self, w_list, start, step, slicelength):
+ items = self.unerase(w_list.lstorage)
+ if slicelength==0:
+ return
+
+ if step < 0:
+ start = start + step * (slicelength-1)
+ step = -step
+
+ if step == 1:
+ assert start >= 0
+ assert slicelength >= 0
+ del items[start:start+slicelength]
+ else:
+ n = len(items)
+ i = start
+
+ for discard in range(1, slicelength):
+ j = i+1
+ i += step
+ while j < i:
+ items[j-discard] = items[j]
+ j += 1
+
+ j = i+1
+ while j < n:
+ items[j-slicelength] = items[j]
+ j += 1
+ start = n - slicelength
+ assert start >= 0 # annotator hint
+ del items[start:]
+
+ def pop_end(self, w_list):
+ l = self.unerase(w_list.lstorage)
+ return self.wrap(l.pop())
+
+ def pop(self, w_list, index):
+ l = self.unerase(w_list.lstorage)
+ # not sure if RPython raises IndexError on pop
+ # so check again here
+ if index < 0:
+ raise IndexError
+ try:
+ item = l.pop(index)
+ except IndexError:
+ raise
+
+ w_item = self.wrap(item)
+ return w_item
+
+ def inplace_mul(self, w_list, times):
+ l = self.unerase(w_list.lstorage)
+ l *= times
+
+ def reverse(self, w_list):
+ self.unerase(w_list.lstorage).reverse()
+
+class ObjectListStrategy(AbstractUnwrappedStrategy, ListStrategy):
+ _none_value = None
+
+ def unwrap(self, w_obj):
+ return w_obj
+
+ def wrap(self, item):
+ return item
+
+ erase, unerase = rerased.new_erasing_pair("object")
+ erase = staticmethod(erase)
+ unerase = staticmethod(unerase)
+
+ def is_correct_type(self, w_obj):
+ return True
+
+ def list_is_correct_type(self, w_list):
+ return w_list.strategy is self.space.fromcache(ObjectListStrategy)
+
+ def init_from_list_w(self, w_list, list_w):
+ w_list.lstorage = self.erase(list_w)
+
+ def contains(self, w_list, w_obj):
+ return ListStrategy.contains(self, w_list, w_obj)
+
+ def getitems(self, w_list):
+ return self.unerase(w_list.lstorage)
+
+class IntegerListStrategy(AbstractUnwrappedStrategy, ListStrategy):
+ _none_value = 0
+
+ def wrap(self, intval):
+ return self.space.wrap(intval)
+
+ def unwrap(self, w_int):
+ return self.space.int_w(w_int)
+
+ erase, unerase = rerased.new_erasing_pair("integer")
+ erase = staticmethod(erase)
+ unerase = staticmethod(unerase)
+
+ def is_correct_type(self, w_obj):
+ return is_W_IntObject(w_obj)
+
+ def list_is_correct_type(self, w_list):
+ return w_list.strategy is self.space.fromcache(IntegerListStrategy)
+
+ def sort(self, w_list, reverse):
+ l = self.unerase(w_list.lstorage)
+ sorter = IntSort(l, len(l))
+ sorter.sort()
+ if reverse:
+ l.reverse()
+
+class StringListStrategy(AbstractUnwrappedStrategy, ListStrategy):
+ _none_value = None
+
+ def wrap(self, stringval):
+ return self.space.wrap(stringval)
+
+ def unwrap(self, w_string):
+ return self.space.str_w(w_string)
+
+ erase, unerase = rerased.new_erasing_pair("string")
+ erase = staticmethod(erase)
+ unerase = staticmethod(unerase)
+
+ def is_correct_type(self, w_obj):
+ return is_W_StringObject(w_obj)
+
+ def list_is_correct_type(self, w_list):
+ return w_list.strategy is self.space.fromcache(StringListStrategy)
+
+ def sort(self, w_list, reverse):
+ l = self.unerase(w_list.lstorage)
+ sorter = StringSort(l, len(l))
+ sorter.sort()
+ if reverse:
+ l.reverse()
+
+ def getitems_str(self, w_list):
+ return self.unerase(w_list.lstorage)
+
+# _______________________________________________________
+
init_signature = Signature(['sequence'], None, None)
init_defaults = [None]
@@ -42,25 +944,24 @@
# this is on the silly side
w_iterable, = __args__.parse_obj(
None, 'list', init_signature, init_defaults)
- items_w = w_list.wrappeditems
- del items_w[:]
+ w_list.__init__(space, [])
if w_iterable is not None:
# unfortunately this is duplicating space.unpackiterable to avoid
# assigning a new RPython list to 'wrappeditems', which defeats the
# W_FastListIterObject optimization.
if isinstance(w_iterable, W_ListObject):
- items_w.extend(w_iterable.wrappeditems)
+ w_list.extend(w_iterable)
elif isinstance(w_iterable, W_TupleObject):
- items_w.extend(w_iterable.wrappeditems)
+ w_list.extend(W_ListObject(space, w_iterable.wrappeditems[:]))
else:
- _init_from_iterable(space, items_w, w_iterable)
+ _init_from_iterable(space, w_list, w_iterable)
-def _init_from_iterable(space, items_w, w_iterable):
+def _init_from_iterable(space, w_list, w_iterable):
# in its own function to make the JIT look into init__List
# xxx special hack for speed
from pypy.interpreter.generator import GeneratorIterator
if isinstance(w_iterable, GeneratorIterator):
- w_iterable.unpack_into(items_w)
+ w_iterable.unpack_into_w(w_list)
return
# /xxx
w_iterator = space.iter(w_iterable)
@@ -71,70 +972,65 @@
if not e.match(space, space.w_StopIteration):
raise
break # done
- items_w.append(w_item)
+ w_list.append(w_item)
def len__List(space, w_list):
- result = len(w_list.wrappeditems)
+ result = w_list.length()
return wrapint(space, result)
def getitem__List_ANY(space, w_list, w_index):
try:
- return w_list.wrappeditems[get_list_index(space, w_index)]
+ return w_list.getitem(get_list_index(space, w_index))
except IndexError:
raise OperationError(space.w_IndexError,
space.wrap("list index out of range"))
def getitem__List_Slice(space, w_list, w_slice):
# XXX consider to extend rlist's functionality?
- length = len(w_list.wrappeditems)
+ length = w_list.length()
start, stop, step, slicelength = w_slice.indices4(space, length)
assert slicelength >= 0
- if step == 1 and 0 <= start <= stop:
- return W_ListObject(w_list.wrappeditems[start:stop])
- w_res = W_ListObject([None] * slicelength)
- items_w = w_list.wrappeditems
- subitems_w = w_res.wrappeditems
- for i in range(slicelength):
- subitems_w[i] = items_w[start]
- start += step
- return w_res
+ if slicelength == 0:
+ return make_empty_list(space)
+ return w_list.getslice(start, stop, step, slicelength)
def getslice__List_ANY_ANY(space, w_list, w_start, w_stop):
- length = len(w_list.wrappeditems)
- start, stop = normalize_simple_slice(space, length, w_start, w_stop)
- return W_ListObject(w_list.wrappeditems[start:stop])
-
-def setslice__List_ANY_ANY_ANY(space, w_list, w_start, w_stop, w_sequence):
- length = len(w_list.wrappeditems)
+ length = w_list.length()
start, stop = normalize_simple_slice(space, length, w_start, w_stop)
- sequence2 = space.listview(w_sequence)
- items = w_list.wrappeditems
- _setitem_slice_helper(space, items, start, 1, stop-start, sequence2,
- empty_elem=None)
+ slicelength = stop - start
+ if slicelength == 0:
+ return make_empty_list(space)
+ return w_list.getslice(start, stop, 1, stop - start)
+
+def setslice__List_ANY_ANY_List(space, w_list, w_start, w_stop, w_other):
+ length = w_list.length()
+ start, stop = normalize_simple_slice(space, length, w_start, w_stop)
+ w_list.setslice(start, 1, stop-start, w_other)
+
+def setslice__List_ANY_ANY_ANY(space, w_list, w_start, w_stop, w_iterable):
+ length = w_list.length()
+ start, stop = normalize_simple_slice(space, length, w_start, w_stop)
+ sequence_w = space.listview(w_iterable)
+ w_other = W_ListObject(space, sequence_w)
+ w_list.setslice(start, 1, stop-start, w_other)
def delslice__List_ANY_ANY(space, w_list, w_start, w_stop):
- length = len(w_list.wrappeditems)
+ length = w_list.length()
start, stop = normalize_simple_slice(space, length, w_start, w_stop)
- _delitem_slice_helper(space, w_list.wrappeditems, start, 1, stop-start)
+ w_list.deleteslice(start, 1, stop-start)
def contains__List_ANY(space, w_list, w_obj):
- # needs to be safe against eq_w() mutating the w_list behind our back
- i = 0
- items_w = w_list.wrappeditems
- while i < len(items_w): # intentionally always calling len!
- if space.eq_w(items_w[i], w_obj):
- return space.w_True
- i += 1
- return space.w_False
+ return space.wrap(w_list.contains(w_obj))
def iter__List(space, w_list):
from pypy.objspace.std import iterobject
- return iterobject.W_FastListIterObject(w_list, w_list.wrappeditems)
+ return iterobject.W_FastListIterObject(w_list)
def add__List_List(space, w_list1, w_list2):
- return W_ListObject(w_list1.wrappeditems + w_list2.wrappeditems)
-
+ w_clone = w_list1.clone()
+ w_clone.extend(w_list2)
+ return w_clone
def inplace_add__List_ANY(space, w_list1, w_iterable2):
try:
@@ -156,7 +1052,7 @@
if e.match(space, space.w_TypeError):
raise FailedToImplement
raise
- return W_ListObject(w_list.wrappeditems * times)
+ return w_list.mul(times)
def mul__List_ANY(space, w_list, w_times):
return mul_list_times(space, w_list, w_times)
@@ -171,63 +1067,65 @@
if e.match(space, space.w_TypeError):
raise FailedToImplement
raise
- w_list.wrappeditems *= times
+ w_list.inplace_mul(times)
return w_list
def eq__List_List(space, w_list1, w_list2):
# needs to be safe against eq_w() mutating the w_lists behind our back
- items1_w = w_list1.wrappeditems
- items2_w = w_list2.wrappeditems
- return equal_wrappeditems(space, items1_w, items2_w)
+ if w_list1.length() != w_list2.length():
+ return space.w_False
-def equal_wrappeditems(space, items1_w, items2_w):
- if len(items1_w) != len(items2_w):
- return space.w_False
+ # XXX in theory, this can be implemented more efficiently as well. let's
+ # not care for now
i = 0
- while i < len(items1_w) and i < len(items2_w):
- if not space.eq_w(items1_w[i], items2_w[i]):
+ while i < w_list1.length() and i < w_list2.length():
+ if not space.eq_w(w_list1.getitem(i), w_list2.getitem(i)):
return space.w_False
i += 1
return space.w_True
-def lessthan_unwrappeditems(space, items1_w, items2_w):
+def lessthan_unwrappeditems(space, w_list1, w_list2):
# needs to be safe against eq_w() mutating the w_lists behind our back
# Search for the first index where items are different
i = 0
- while i < len(items1_w) and i < len(items2_w):
- w_item1 = items1_w[i]
- w_item2 = items2_w[i]
+ # XXX in theory, this can be implemented more efficiently as well. let's
+ # not care for now
+ while i < w_list1.length() and i < w_list2.length():
+ w_item1 = w_list1.getitem(i)
+ w_item2 = w_list2.getitem(i)
if not space.eq_w(w_item1, w_item2):
return space.lt(w_item1, w_item2)
i += 1
# No more items to compare -- compare sizes
- return space.newbool(len(items1_w) < len(items2_w))
+ return space.newbool(w_list1.length() < w_list2.length())
-def greaterthan_unwrappeditems(space, items1_w, items2_w):
+def greaterthan_unwrappeditems(space, w_list1, w_list2):
# needs to be safe against eq_w() mutating the w_lists behind our back
# Search for the first index where items are different
i = 0
- while i < len(items1_w) and i < len(items2_w):
- w_item1 = items1_w[i]
- w_item2 = items2_w[i]
+ # XXX in theory, this can be implemented more efficiently as well. let's
+ # not care for now
+ while i < w_list1.length() and i < w_list2.length():
+ w_item1 = w_list1.getitem(i)
+ w_item2 = w_list2.getitem(i)
if not space.eq_w(w_item1, w_item2):
return space.gt(w_item1, w_item2)
i += 1
# No more items to compare -- compare sizes
- return space.newbool(len(items1_w) > len(items2_w))
+ return space.newbool(w_list1.length() > w_list2.length())
def lt__List_List(space, w_list1, w_list2):
- return lessthan_unwrappeditems(space, w_list1.wrappeditems,
- w_list2.wrappeditems)
+ return lessthan_unwrappeditems(space, w_list1, w_list2)
def gt__List_List(space, w_list1, w_list2):
- return greaterthan_unwrappeditems(space, w_list1.wrappeditems,
- w_list2.wrappeditems)
+ return greaterthan_unwrappeditems(space, w_list1, w_list2)
def delitem__List_ANY(space, w_list, w_idx):
idx = get_list_index(space, w_idx)
+ if idx < 0:
+ idx += w_list.length()
try:
- del w_list.wrappeditems[idx]
+ w_list.pop(idx)
except IndexError:
raise OperationError(space.w_IndexError,
space.wrap("list deletion index out of range"))
@@ -235,103 +1133,29 @@
def delitem__List_Slice(space, w_list, w_slice):
- start, stop, step, slicelength = w_slice.indices4(space,
- len(w_list.wrappeditems))
- _delitem_slice_helper(space, w_list.wrappeditems, start, step, slicelength)
-
-def _delitem_slice_helper(space, items, start, step, slicelength):
- if slicelength==0:
- return
-
- if step < 0:
- start = start + step * (slicelength-1)
- step = -step
-
- if step == 1:
- assert start >= 0
- assert slicelength >= 0
- del items[start:start+slicelength]
- else:
- n = len(items)
- i = start
-
- for discard in range(1, slicelength):
- j = i+1
- i += step
- while j < i:
- items[j-discard] = items[j]
- j += 1
-
- j = i+1
- while j < n:
- items[j-slicelength] = items[j]
- j += 1
- start = n - slicelength
- assert start >= 0 # annotator hint
- del items[start:]
+ start, stop, step, slicelength = w_slice.indices4(space, w_list.length())
+ w_list.deleteslice(start, step, slicelength)
def setitem__List_ANY_ANY(space, w_list, w_index, w_any):
idx = get_list_index(space, w_index)
try:
- w_list.wrappeditems[idx] = w_any
+ w_list.setitem(idx, w_any)
except IndexError:
raise OperationError(space.w_IndexError,
space.wrap("list index out of range"))
return space.w_None
+def setitem__List_Slice_List(space, w_list, w_slice, w_other):
+ oldsize = w_list.length()
+ start, stop, step, slicelength = w_slice.indices4(space, oldsize)
+ w_list.setslice(start, step, slicelength, w_other)
+
def setitem__List_Slice_ANY(space, w_list, w_slice, w_iterable):
- oldsize = len(w_list.wrappeditems)
+ oldsize = w_list.length()
start, stop, step, slicelength = w_slice.indices4(space, oldsize)
-
- sequence2 = space.listview(w_iterable)
- items = w_list.wrappeditems
- _setitem_slice_helper(space, items, start, step, slicelength, sequence2,
- empty_elem=None)
-
-def _setitem_slice_helper(space, items, start, step, slicelength, sequence2,
- empty_elem):
- assert slicelength >= 0
- oldsize = len(items)
- len2 = len(sequence2)
- if step == 1: # Support list resizing for non-extended slices
- delta = slicelength - len2
- if delta < 0:
- delta = -delta
- newsize = oldsize + delta
- # XXX support this in rlist!
- items += [empty_elem] * delta
- lim = start+len2
- i = newsize - 1
- while i >= lim:
- items[i] = items[i-delta]
- i -= 1
- elif start >= 0:
- del items[start:start+delta]
- else:
- assert delta==0 # start<0 is only possible with slicelength==0
- elif len2 != slicelength: # No resize for extended slices
- raise operationerrfmt(space.w_ValueError, "attempt to "
- "assign sequence of size %d to extended slice of size %d",
- len2, slicelength)
-
- if sequence2 is items:
- if step > 0:
- # Always copy starting from the right to avoid
- # having to make a shallow copy in the case where
- # the source and destination lists are the same list.
- i = len2 - 1
- start += i*step
- while i >= 0:
- items[start] = sequence2[i]
- start -= step
- i -= 1
- return
- else:
- # Make a shallow copy to more easily handle the reversal case
- sequence2 = list(sequence2)
- for i in range(len2):
- items[start] = sequence2[i]
- start += step
+ sequence_w = space.listview(w_iterable)
+ w_other = W_ListObject(space, sequence_w)
+ w_list.setslice(start, step, slicelength, w_other)
app = gateway.applevel("""
def listrepr(currently_in_repr, l):
@@ -352,7 +1176,7 @@
listrepr = app.interphook("listrepr")
def repr__List(space, w_list):
- if len(w_list.wrappeditems) == 0:
+ if w_list.length() == 0:
return space.wrap('[]')
ec = space.getexecutioncontext()
w_currently_in_repr = ec._py_repr
@@ -362,9 +1186,9 @@
def list_insert__List_ANY_ANY(space, w_list, w_where, w_any):
where = space.int_w(w_where)
- length = len(w_list.wrappeditems)
+ length = w_list.length()
index = get_positive_index(where, length)
- w_list.wrappeditems.insert(index, w_any)
+ w_list.insert(index, w_any)
return space.w_None
def get_positive_index(where, length):
@@ -374,45 +1198,51 @@
where = 0
elif where > length:
where = length
+ assert where >= 0
return where
def list_append__List_ANY(space, w_list, w_any):
- w_list.wrappeditems.append(w_any)
+ w_list.append(w_any)
return space.w_None
def list_extend__List_List(space, w_list, w_other):
- w_list.wrappeditems += w_other.wrappeditems
+ w_list.extend(w_other)
return space.w_None
def list_extend__List_ANY(space, w_list, w_any):
- w_list.wrappeditems += space.listview(w_any)
+ w_other = W_ListObject(space, space.listview(w_any))
+ w_list.extend(w_other)
return space.w_None
-# note that the default value will come back wrapped!!!
-def list_pop__List_ANY(space, w_list, w_idx=-1):
- items = w_list.wrappeditems
- if len(items)== 0:
+# default of w_idx is space.w_None (see listtype.py)
+def list_pop__List_ANY(space, w_list, w_idx):
+ length = w_list.length()
+ if length == 0:
raise OperationError(space.w_IndexError,
space.wrap("pop from empty list"))
+ # clearly differentiate between list.pop() and list.pop(index)
+ if space.is_w(w_idx, space.w_None):
+ return w_list.pop_end() # cannot raise because list is not empty
if space.isinstance_w(w_idx, space.w_float):
raise OperationError(space.w_TypeError,
space.wrap("integer argument expected, got float")
)
idx = space.int_w(space.int(w_idx))
+ if idx < 0:
+ idx += length
try:
- return items.pop(idx)
+ return w_list.pop(idx)
except IndexError:
raise OperationError(space.w_IndexError,
space.wrap("pop index out of range"))
def list_remove__List_ANY(space, w_list, w_any):
# needs to be safe against eq_w() mutating the w_list behind our back
- items = w_list.wrappeditems
i = 0
- while i < len(items):
- if space.eq_w(items[i], w_any):
- if i < len(items): # if this is wrong the list was changed
- del items[i]
+ while i < w_list.length():
+ if space.eq_w(w_list.getitem(i), w_any):
+ if i < w_list.length(): # if this is wrong the list was changed
+ w_list.pop(i)
return space.w_None
i += 1
raise OperationError(space.w_ValueError,
@@ -420,12 +1250,11 @@
def list_index__List_ANY_ANY_ANY(space, w_list, w_any, w_start, w_stop):
# needs to be safe against eq_w() mutating the w_list behind our back
- items = w_list.wrappeditems
- size = len(items)
+ size = w_list.length()
i, stop = slicetype.unwrap_start_stop(
space, size, w_start, w_stop, True)
- while i < stop and i < len(items):
- if space.eq_w(items[i], w_any):
+ while i < stop and i < w_list.length():
+ if space.eq_w(w_list.getitem(i), w_any):
return space.wrap(i)
i += 1
raise OperationError(space.w_ValueError,
@@ -435,15 +1264,14 @@
# needs to be safe against eq_w() mutating the w_list behind our back
count = 0
i = 0
- items = w_list.wrappeditems
- while i < len(items):
- if space.eq_w(items[i], w_any):
+ while i < w_list.length():
+ if space.eq_w(w_list.getitem(i), w_any):
count += 1
i += 1
return space.wrap(count)
def list_reverse__List(space, w_list):
- w_list.wrappeditems.reverse()
+ w_list.reverse()
return space.w_None
# ____________________________________________________________
@@ -452,12 +1280,15 @@
# Reverse a slice of a list in place, from lo up to (exclusive) hi.
# (used in sort)
+TimSort = make_timsort_class()
+IntBaseTimSort = make_timsort_class()
+StringBaseTimSort = make_timsort_class()
+
class KeyContainer(baseobjspace.W_Root):
def __init__(self, w_key, w_item):
self.w_key = w_key
self.w_item = w_item
-TimSort = make_timsort_class()
# NOTE: all the subclasses of TimSort should inherit from a common subclass,
# so make sure that only SimpleSort inherits directly from TimSort.
# This is necessary to hide the parent method TimSort.lt() from the
@@ -467,6 +1298,14 @@
space = self.space
return space.is_true(space.lt(a, b))
+class IntSort(IntBaseTimSort):
+ def lt(self, a, b):
+ return a < b
+
+class StringSort(StringBaseTimSort):
+ def lt(self, a, b):
+ return a < b
+
class CustomCompareSort(SimpleSort):
def lt(self, a, b):
space = self.space
@@ -495,6 +1334,7 @@
return CustomCompareSort.lt(self, a.w_key, b.w_key)
def list_sort__List_ANY_ANY_ANY(space, w_list, w_cmp, w_keyfunc, w_reverse):
+
has_cmp = not space.is_w(w_cmp, space.w_None)
has_key = not space.is_w(w_keyfunc, space.w_None)
has_reverse = space.is_true(w_reverse)
@@ -509,9 +1349,13 @@
if has_key:
sorterclass = CustomKeySort
else:
- sorterclass = SimpleSort
- items = w_list.wrappeditems
- sorter = sorterclass(items, len(items))
+ if w_list.strategy is space.fromcache(ObjectListStrategy):
+ sorterclass = SimpleSort
+ else:
+ w_list.sort(has_reverse)
+ return space.w_None
+
+ sorter = sorterclass(w_list.getitems(), w_list.length())
sorter.space = space
sorter.w_cmp = w_cmp
@@ -519,8 +1363,8 @@
# The list is temporarily made empty, so that mutations performed
# by comparison functions can't affect the slice of memory we're
# sorting (allowing mutations during sorting is an IndexError or
- # core-dump factory, since wrappeditems may change).
- w_list.wrappeditems = []
+ # core-dump factory, since the storage may change).
+ w_list.__init__(space, [])
# wrap each item in a KeyContainer if needed
if has_key:
@@ -550,10 +1394,10 @@
sorter.list[i] = w_obj.w_item
# check if the user mucked with the list during the sort
- mucked = len(w_list.wrappeditems) > 0
+ mucked = w_list.length() > 0
# put the items back into the list
- w_list.wrappeditems = sorter.list
+ w_list.__init__(space, sorter.list)
if mucked:
raise OperationError(space.w_ValueError,
diff --git a/pypy/objspace/std/listtype.py b/pypy/objspace/std/listtype.py
--- a/pypy/objspace/std/listtype.py
+++ b/pypy/objspace/std/listtype.py
@@ -11,7 +11,7 @@
list_extend = SMM('extend', 2,
doc='L.extend(iterable) -- extend list by appending'
' elements from the iterable')
-list_pop = SMM('pop', 2, defaults=(-1,),
+list_pop = SMM('pop', 2, defaults=(None,),
doc='L.pop([index]) -> item -- remove and return item at'
' index (default last)')
list_remove = SMM('remove', 2,
@@ -43,7 +43,7 @@
def descr__new__(space, w_listtype, __args__):
from pypy.objspace.std.listobject import W_ListObject
w_obj = space.allocate_instance(W_ListObject, w_listtype)
- W_ListObject.__init__(w_obj, [])
+ W_ListObject.__init__(w_obj, space, [])
return w_obj
# ____________________________________________________________
diff --git a/pypy/objspace/std/longobject.py b/pypy/objspace/std/longobject.py
--- a/pypy/objspace/std/longobject.py
+++ b/pypy/objspace/std/longobject.py
@@ -11,6 +11,22 @@
class W_AbstractLongObject(W_Object):
__slots__ = ()
+ def is_w(self, space, w_other):
+ if not isinstance(w_other, W_AbstractLongObject):
+ return False
+ if self.user_overridden_class or w_other.user_overridden_class:
+ return self is w_other
+ return space.bigint_w(self).eq(space.bigint_w(w_other))
+
+ def unique_id(self, space):
+ if self.user_overridden_class:
+ return W_Object.unique_id(self, space)
+ from pypy.objspace.std.model import IDTAG_LONG as tag
+ b = space.bigint_w(self)
+ b = b.lshift(3).or_(rbigint.fromint(tag))
+ return space.newlong_from_rbigint(b)
+
+
class W_LongObject(W_AbstractLongObject):
"""This is a wrapper of rbigint."""
from pypy.objspace.std.longtype import long_typedef as typedef
diff --git a/pypy/objspace/std/marshal_impl.py b/pypy/objspace/std/marshal_impl.py
--- a/pypy/objspace/std/marshal_impl.py
+++ b/pypy/objspace/std/marshal_impl.py
@@ -300,7 +300,7 @@
register(TYPE_TUPLE, unmarshal_Tuple)
def marshal_w__List(space, w_list, m):
- items = w_list.wrappeditems[:]
+ items = w_list.getitems()[:]
m.put_tuple_w(TYPE_LIST, items)
def unmarshal_List(space, u, tc):
diff --git a/pypy/objspace/std/model.py b/pypy/objspace/std/model.py
--- a/pypy/objspace/std/model.py
+++ b/pypy/objspace/std/model.py
@@ -25,12 +25,15 @@
"ropeobject.W_RopeIterObject"],
"withropeunicode": ["ropeunicodeobject.W_RopeUnicodeObject",
"ropeunicodeobject.W_RopeUnicodeIterObject"],
- "withrangelist" : ["rangeobject.W_RangeListObject",
- "rangeobject.W_RangeIterObject"],
"withtproxy" : ["proxyobject.W_TransparentList",
"proxyobject.W_TransparentDict"],
}
+IDTAG_INT = 1
+IDTAG_LONG = 3
+IDTAG_FLOAT = 5
+IDTAG_COMPLEX = 7
+
class StdTypeModel:
def __init__(self, config):
@@ -253,12 +256,6 @@
(unicodeobject.W_UnicodeObject,
strbufobject.delegate_buf2unicode)
]
- if config.objspace.std.withrangelist:
- from pypy.objspace.std import rangeobject
- self.typeorder[rangeobject.W_RangeListObject] += [
- (listobject.W_ListObject,
- rangeobject.delegate_range2list),
- ]
if config.objspace.std.withsmalltuple:
from pypy.objspace.std import smalltupleobject
self.typeorder[smalltupleobject.W_SmallTupleObject] += [
diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py
--- a/pypy/objspace/std/objspace.py
+++ b/pypy/objspace/std/objspace.py
@@ -301,7 +301,10 @@
return wraptuple(self, list_w)
def newlist(self, list_w):
- return W_ListObject(list_w)
+ return W_ListObject(self, list_w)
+
+ def newlist_str(self, list_s):
+ return W_ListObject.newlist_str(self, list_s)
def newdict(self, module=False, instance=False, classofinstance=None,
strdict=False):
@@ -391,7 +394,7 @@
if isinstance(w_obj, W_TupleObject):
t = w_obj.wrappeditems[:]
elif isinstance(w_obj, W_ListObject):
- t = w_obj.wrappeditems[:]
+ t = w_obj.getitems_copy()
else:
return ObjSpace.unpackiterable(self, w_obj, expected_length)
if expected_length != -1 and len(t) != expected_length:
@@ -405,7 +408,8 @@
if isinstance(w_obj, W_TupleObject):
t = w_obj.wrappeditems
elif isinstance(w_obj, W_ListObject):
- t = w_obj.wrappeditems[:]
+ # XXX this can copy twice
+ t = w_obj.getitems()[:]
else:
if unroll:
return make_sure_not_resized(ObjSpace.unpackiterable_unroll(
@@ -423,7 +427,7 @@
def listview(self, w_obj, expected_length=-1):
if isinstance(w_obj, W_ListObject):
- t = w_obj.wrappeditems
+ t = w_obj.getitems()
elif isinstance(w_obj, W_TupleObject):
t = w_obj.wrappeditems[:]
else:
@@ -432,6 +436,11 @@
raise self._wrap_expected_length(expected_length, len(t))
return t
+ def listview_str(self, w_obj):
+ if isinstance(w_obj, W_ListObject):
+ return w_obj.getitems_str()
+ return None
+
def sliceindices(self, w_slice, w_length):
if isinstance(w_slice, W_SliceObject):
a, b, c = w_slice.indices3(self, self.int_w(w_length))
@@ -444,15 +453,6 @@
self.wrap("Expected tuple of length 3"))
return self.int_w(l_w[0]), self.int_w(l_w[1]), self.int_w(l_w[2])
- def is_(self, w_one, w_two):
- if w_one is w_two:
- return self.w_True
- return self.w_False
-
- # short-cut
- def is_w(self, w_one, w_two):
- return w_one is w_two
-
def is_true(self, w_obj):
# a shortcut for performance
# NOTE! this method is typically overridden by builtinshortcut.py.
diff --git a/pypy/objspace/std/rangeobject.py b/pypy/objspace/std/rangeobject.py
deleted file mode 100644
--- a/pypy/objspace/std/rangeobject.py
+++ /dev/null
@@ -1,237 +0,0 @@
-from pypy.interpreter.error import OperationError
-from pypy.objspace.std.model import registerimplementation, W_Object
-from pypy.objspace.std.register_all import register_all
-from pypy.objspace.std.multimethod import FailedToImplement
-from pypy.objspace.std.noneobject import W_NoneObject
-from pypy.objspace.std.inttype import wrapint
-from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice
-from pypy.objspace.std.listobject import W_AbstractListObject, W_ListObject
-from pypy.objspace.std import listtype, iterobject, slicetype
-from pypy.interpreter import gateway, baseobjspace
-
-def length(start, stop, step):
- if step > 0:
- if stop <= start:
- return 0
- return (stop - start + step - 1)/step
-
- else: # step must be < 0
- if stop >= start:
- return 0
- return (start - stop - step - 1)/-step
-
-
-class W_RangeListObject(W_AbstractListObject):
- typedef = listtype.list_typedef
-
- def __init__(w_self, start, step, length):
- assert step != 0
- w_self.start = start
- w_self.step = step
- w_self.length = length
- w_self.w_list = None
-
- def force(w_self, space):
- if w_self.w_list is not None:
- return w_self.w_list
- start = w_self.start
- step = w_self.step
- length = w_self.length
- if not length:
- w_self.w_list = space.newlist([])
- return w_self.w_list
-
- arr = [None] * length # this is to avoid using append.
-
- i = start
- n = 0
- while n < length:
- arr[n] = wrapint(space, i)
- i += step
- n += 1
-
- w_self.w_list = space.newlist(arr)
- return w_self.w_list
-
- def getitem(w_self, i):
- if i < 0:
- i += w_self.length
- if i < 0:
- raise IndexError
- elif i >= w_self.length:
- raise IndexError
- return w_self.start + i * w_self.step
-
- def getitem_unchecked(w_self, i):
- # bounds not checked, on purpose
- return w_self.start + i * w_self.step
-
- def __repr__(w_self):
- if w_self.w_list is None:
- return "W_RangeListObject(%s, %s, %s)" % (
- w_self.start, w_self.step, w_self.length)
- else:
- return "W_RangeListObject(%r)" % (w_self.w_list, )
-
-def delegate_range2list(space, w_rangelist):
- return w_rangelist.force(space)
-
-def len__RangeList(space, w_rangelist):
- if w_rangelist.w_list is not None:
- return space.len(w_rangelist.w_list)
- return wrapint(space, w_rangelist.length)
-
-
-def getitem__RangeList_ANY(space, w_rangelist, w_index):
- if w_rangelist.w_list is not None:
- return space.getitem(w_rangelist.w_list, w_index)
- idx = space.getindex_w(w_index, space.w_IndexError, "list index")
- try:
- return wrapint(space, w_rangelist.getitem(idx))
- except IndexError:
- raise OperationError(space.w_IndexError,
- space.wrap("list index out of range"))
-
-def getitem__RangeList_Slice(space, w_rangelist, w_slice):
- if w_rangelist.w_list is not None:
- return space.getitem(w_rangelist.w_list, w_slice)
- length = w_rangelist.length
- start, stop, step, slicelength = w_slice.indices4(space, length)
- assert slicelength >= 0
- rangestart = w_rangelist.getitem_unchecked(start)
- rangestep = w_rangelist.step * step
- return W_RangeListObject(rangestart, rangestep, slicelength)
-
-def getslice__RangeList_ANY_ANY(space, w_rangelist, w_start, w_stop):
- if w_rangelist.w_list is not None:
- return space.getslice(w_rangelist.w_list, w_start, w_stop)
- length = w_rangelist.length
- start, stop = normalize_simple_slice(space, length, w_start, w_stop)
- slicelength = stop - start
- assert slicelength >= 0
- rangestart = w_rangelist.getitem_unchecked(start)
- rangestep = w_rangelist.step
- return W_RangeListObject(rangestart, rangestep, slicelength)
-
-def iter__RangeList(space, w_rangelist):
- return W_RangeIterObject(w_rangelist)
-
-def repr__RangeList(space, w_rangelist):
- if w_rangelist.w_list is not None:
- return space.repr(w_rangelist.w_list)
- if w_rangelist.length == 0:
- return space.wrap('[]')
- result = [''] * w_rangelist.length
- i = w_rangelist.start
- n = 0
- while n < w_rangelist.length:
- result[n] = str(i)
- i += w_rangelist.step
- n += 1
- return space.wrap("[" + ", ".join(result) + "]")
-
-def inplace_add__RangeList_ANY(space, w_rangelist, w_iterable2):
- space.inplace_add(w_rangelist.force(space), w_iterable2)
- return w_rangelist
-
-def inplace_mul__RangeList_ANY(space, w_rangelist, w_number):
- space.inplace_mul(w_rangelist.force(space), w_number)
- return w_rangelist
-
-
-def list_pop__RangeList_ANY(space, w_rangelist, w_idx=-1):
- if w_rangelist.w_list is not None:
- raise FailedToImplement
- length = w_rangelist.length
- if length == 0:
- raise OperationError(space.w_IndexError,
- space.wrap("pop from empty list"))
- if space.isinstance_w(w_idx, space.w_float):
- raise OperationError(space.w_TypeError,
- space.wrap("integer argument expected, got float")
- )
- idx = space.int_w(space.int(w_idx))
- if idx == 0:
- result = w_rangelist.start
- w_rangelist.start += w_rangelist.step
- w_rangelist.length -= 1
- return wrapint(space, result)
- if idx == -1 or idx == length - 1:
- w_rangelist.length -= 1
- return wrapint(
- space, w_rangelist.start + (length - 1) * w_rangelist.step)
- if idx >= w_rangelist.length:
- raise OperationError(space.w_IndexError,
- space.wrap("pop index out of range"))
- raise FailedToImplement
-
-def list_reverse__RangeList(space, w_rangelist):
- # probably somewhat useless, but well...
- if w_rangelist.w_list is not None:
- raise FailedToImplement
- w_rangelist.start = w_rangelist.getitem_unchecked(w_rangelist.length-1)
- w_rangelist.step = -w_rangelist.step
-
-def list_sort__RangeList_None_None_ANY(space, w_rangelist, w_cmp,
- w_keyfunc, w_reverse):
- # even more useless but fun
- has_reverse = space.is_true(w_reverse)
- if w_rangelist.w_list is not None:
- raise FailedToImplement
- if has_reverse:
- factor = -1
- else:
- factor = 1
- reverse = w_rangelist.step * factor < 0
- if reverse:
- w_rangelist.start = w_rangelist.getitem_unchecked(w_rangelist.length-1)
- w_rangelist.step = -w_rangelist.step
- return space.w_None
-
-
-class W_RangeIterObject(iterobject.W_AbstractSeqIterObject):
- pass
-
-def iter__RangeIter(space, w_rangeiter):
- return w_rangeiter
-
-def next__RangeIter(space, w_rangeiter):
- w_rangelist = w_rangeiter.w_seq
- if w_rangelist is None:
- raise OperationError(space.w_StopIteration, space.w_None)
- assert isinstance(w_rangelist, W_RangeListObject)
- index = w_rangeiter.index
- if w_rangelist.w_list is not None:
- try:
- w_item = space.getitem(w_rangelist.w_list,
- wrapint(space, index))
- except OperationError, e:
- w_rangeiter.w_seq = None
- if not e.match(space, space.w_IndexError):
- raise
- raise OperationError(space.w_StopIteration, space.w_None)
- else:
- if index >= w_rangelist.length:
- w_rangeiter.w_seq = None
- raise OperationError(space.w_StopIteration, space.w_None)
- w_item = wrapint(
- space,
- w_rangelist.getitem_unchecked(index))
- w_rangeiter.index = index + 1
- return w_item
-
-# XXX __length_hint__()
-##def len__RangeIter(space, w_rangeiter):
-## if w_rangeiter.w_seq is None:
-## return wrapint(space, 0)
-## index = w_rangeiter.index
-## w_length = space.len(w_rangeiter.w_seq)
-## w_len = space.sub(w_length, wrapint(space, index))
-## if space.is_true(space.lt(w_len, wrapint(space, 0))):
-## w_len = wrapint(space, 0)
-## return w_len
-
-registerimplementation(W_RangeListObject)
-registerimplementation(W_RangeIterObject)
-
-register_all(vars(), listtype)
diff --git a/pypy/objspace/std/stringobject.py b/pypy/objspace/std/stringobject.py
--- a/pypy/objspace/std/stringobject.py
+++ b/pypy/objspace/std/stringobject.py
@@ -5,13 +5,14 @@
from pypy.interpreter import gateway
from pypy.rlib.rarithmetic import ovfcheck
from pypy.rlib.objectmodel import we_are_translated, compute_hash, specialize
+from pypy.rlib.objectmodel import compute_unique_id
from pypy.objspace.std.inttype import wrapint
from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice
from pypy.objspace.std import slicetype, newformat
from pypy.objspace.std.listobject import W_ListObject
from pypy.objspace.std.noneobject import W_NoneObject
from pypy.objspace.std.tupleobject import W_TupleObject
-from pypy.rlib.rstring import StringBuilder
+from pypy.rlib.rstring import StringBuilder, split
from pypy.interpreter.buffer import StringBuffer
from pypy.objspace.std.stringtype import sliced, wrapstr, wrapchar, \
@@ -22,6 +23,21 @@
class W_AbstractStringObject(W_Object):
__slots__ = ()
+ def is_w(self, space, w_other):
+ if not isinstance(w_other, W_AbstractStringObject):
+ return False
+ if self is w_other:
+ return True
+ if self.user_overridden_class or w_other.user_overridden_class:
+ return False
+ return space.str_w(self) is space.str_w(w_other)
+
+ def unique_id(self, space):
+ if self.user_overridden_class:
+ return W_Object.unique_id(self, space)
+ return space.wrap(compute_unique_id(space.str_w(self)))
+
+
class W_StringObject(W_AbstractStringObject):
from pypy.objspace.std.stringtype import str_typedef as typedef
_immutable_fields_ = ['_value']
@@ -220,7 +236,7 @@
def str_split__String_None_ANY(space, w_self, w_none, w_maxsplit=-1):
maxsplit = space.int_w(w_maxsplit)
- res_w = []
+ res = []
value = w_self._value
length = len(value)
i = 0
@@ -243,12 +259,12 @@
maxsplit -= 1 # NB. if it's already < 0, it stays < 0
# the word is value[i:j]
- res_w.append(sliced(space, value, i, j, w_self))
+ res.append(value[i:j])
# continue to look from the character following the space after the word
i = j + 1
- return space.newlist(res_w)
+ return space.newlist_str(res)
def str_split__String_String_ANY(space, w_self, w_by, w_maxsplit=-1):
maxsplit = space.int_w(w_maxsplit)
@@ -258,33 +274,26 @@
if bylen == 0:
raise OperationError(space.w_ValueError, space.wrap("empty separator"))
- res_w = []
- start = 0
if bylen == 1 and maxsplit < 0:
+ res = []
+ start = 0
# fast path: uses str.rfind(character) and str.count(character)
by = by[0] # annotator hack: string -> char
count = value.count(by)
- res_w = [None] * (count + 1)
+ res = [None] * (count + 1)
end = len(value)
while count >= 0:
assert end >= 0
prev = value.rfind(by, 0, end)
start = prev + 1
assert start >= 0
- res_w[count] = sliced(space, value, start, end, w_self)
+ res[count] = value[start:end]
count -= 1
end = prev
else:
- while maxsplit != 0:
- next = value.find(by, start)
- if next < 0:
- break
- res_w.append(sliced(space, value, start, next, w_self))
- start = next + bylen
- maxsplit -= 1 # NB. if it's already < 0, it stays < 0
- res_w.append(sliced(space, value, start, len(value), w_self))
+ res = split(value, by, maxsplit)
- return space.newlist(res_w)
+ return space.newlist_str(res)
def str_rsplit__String_None_ANY(space, w_self, w_none, w_maxsplit=-1):
maxsplit = space.int_w(w_maxsplit)
@@ -352,6 +361,11 @@
sliced)
def str_join__String_ANY(space, w_self, w_list):
+ l = space.listview_str(w_list)
+ if l is not None:
+ if len(l) == 1:
+ return space.wrap(l[0])
+ return space.wrap(w_self._value.join(l))
list_w = space.listview(w_list)
size = len(list_w)
diff --git a/pypy/objspace/std/test/test_dictmultiobject.py b/pypy/objspace/std/test/test_dictmultiobject.py
--- a/pypy/objspace/std/test/test_dictmultiobject.py
+++ b/pypy/objspace/std/test/test_dictmultiobject.py
@@ -577,15 +577,17 @@
assert getattr(a, s) == 42
def test_setattr_string_identify(self):
- attrs = []
+ class StrHolder(object):
+ pass
+ holder = StrHolder()
class A(object):
def __setattr__(self, attr, value):
- attrs.append(attr)
+ holder.seen = attr
a = A()
s = "abc"
setattr(a, s, 123)
- assert attrs[0] is s
+ assert holder.seen is s
class AppTestDictViews:
def test_dictview(self):
diff --git a/pypy/objspace/std/test/test_listobject.py b/pypy/objspace/std/test/test_listobject.py
--- a/pypy/objspace/std/test/test_listobject.py
+++ b/pypy/objspace/std/test/test_listobject.py
@@ -1,3 +1,4 @@
+# coding: iso-8859-15
import random
from pypy.objspace.std.listobject import W_ListObject
from pypy.interpreter.error import OperationError
@@ -8,25 +9,25 @@
class TestW_ListObject(object):
def test_is_true(self):
w = self.space.wrap
- w_list = W_ListObject([])
+ w_list = W_ListObject(self.space, [])
assert self.space.is_true(w_list) == False
- w_list = W_ListObject([w(5)])
+ w_list = W_ListObject(self.space, [w(5)])
assert self.space.is_true(w_list) == True
- w_list = W_ListObject([w(5), w(3)])
+ w_list = W_ListObject(self.space, [w(5), w(3)])
assert self.space.is_true(w_list) == True
def test_len(self):
w = self.space.wrap
- w_list = W_ListObject([])
+ w_list = W_ListObject(self.space, [])
assert self.space.eq_w(self.space.len(w_list), w(0))
- w_list = W_ListObject([w(5)])
+ w_list = W_ListObject(self.space, [w(5)])
assert self.space.eq_w(self.space.len(w_list), w(1))
- w_list = W_ListObject([w(5), w(3), w(99)]*111)
+ w_list = W_ListObject(self.space, [w(5), w(3), w(99)]*111)
assert self.space.eq_w(self.space.len(w_list), w(333))
-
+
def test_getitem(self):
w = self.space.wrap
- w_list = W_ListObject([w(5), w(3)])
+ w_list = W_ListObject(self.space, [w(5), w(3)])
assert self.space.eq_w(self.space.getitem(w_list, w(0)), w(5))
assert self.space.eq_w(self.space.getitem(w_list, w(1)), w(3))
assert self.space.eq_w(self.space.getitem(w_list, w(-2)), w(5))
@@ -38,10 +39,19 @@
self.space.raises_w(self.space.w_IndexError,
self.space.getitem, w_list, w(-3))
+ def test_getitems(self):
+ w = self.space.wrap
+ from pypy.objspace.std.listobject import make_range_list
+ r = make_range_list(self.space, 1,1,7)
+ l = [w(1),w(2),w(3),w(4),w(5),w(6),w(7)]
+ l2 = r.getitems()
+ for i in range(7):
+ assert self.space.eq_w(l[i], l2[i])
+
def test_random_getitem(self):
w = self.space.wrap
s = list('qedx387tn3uixhvt 7fh387fymh3dh238 dwd-wq.dwq9')
- w_list = W_ListObject(map(w, s))
+ w_list = W_ListObject(self.space, map(w, s))
keys = range(-len(s)-5, len(s)+5)
choices = keys + [None]*12
stepchoices = [None, None, None, 1, 1, -1, -1, 2, -2,
@@ -64,7 +74,7 @@
def test_iter(self):
w = self.space.wrap
- w_list = W_ListObject([w(5), w(3), w(99)])
+ w_list = W_ListObject(self.space, [w(5), w(3), w(99)])
w_iter = self.space.iter(w_list)
assert self.space.eq_w(self.space.next(w_iter), w(5))
assert self.space.eq_w(self.space.next(w_iter), w(3))
@@ -74,7 +84,7 @@
def test_contains(self):
w = self.space.wrap
- w_list = W_ListObject([w(5), w(3), w(99)])
+ w_list = W_ListObject(self.space, [w(5), w(3), w(99)])
assert self.space.eq_w(self.space.contains(w_list, w(5)),
self.space.w_True)
assert self.space.eq_w(self.space.contains(w_list, w(99)),
@@ -89,10 +99,10 @@
def test1(testlist, start, stop, step, expected):
w_slice = self.space.newslice(w(start), w(stop), w(step))
- w_list = W_ListObject([w(i) for i in testlist])
+ w_list = W_ListObject(self.space, [w(i) for i in testlist])
w_result = self.space.getitem(w_list, w_slice)
assert self.space.unwrap(w_result) == expected
-
+
for testlist in [[], [5,3,99]]:
for start in [-2, 0, 1, 10]:
for end in [-1, 2, 999]:
@@ -110,11 +120,11 @@
def test1(lhslist, start, stop, rhslist, expected):
w_slice = self.space.newslice(w(start), w(stop), w(1))
- w_lhslist = W_ListObject([w(i) for i in lhslist])
- w_rhslist = W_ListObject([w(i) for i in rhslist])
+ w_lhslist = W_ListObject(self.space, [w(i) for i in lhslist])
+ w_rhslist = W_ListObject(self.space, [w(i) for i in rhslist])
self.space.setitem(w_lhslist, w_slice, w_rhslist)
assert self.space.unwrap(w_lhslist) == expected
-
+
test1([5,7,1,4], 1, 3, [9,8], [5,9,8,4])
test1([5,7,1,4], 1, 3, [9], [5,9,4])
@@ -125,14 +135,14 @@
def test_add(self):
w = self.space.wrap
- w_list0 = W_ListObject([])
- w_list1 = W_ListObject([w(5), w(3), w(99)])
- w_list2 = W_ListObject([w(-7)] * 111)
+ w_list0 = W_ListObject(self.space, [])
+ w_list1 = W_ListObject(self.space, [w(5), w(3), w(99)])
+ w_list2 = W_ListObject(self.space, [w(-7)] * 111)
assert self.space.eq_w(self.space.add(w_list1, w_list1),
- W_ListObject([w(5), w(3), w(99),
+ W_ListObject(self.space, [w(5), w(3), w(99),
w(5), w(3), w(99)]))
assert self.space.eq_w(self.space.add(w_list1, w_list2),
- W_ListObject([w(5), w(3), w(99)] +
+ W_ListObject(self.space, [w(5), w(3), w(99)] +
[w(-7)] * 111))
assert self.space.eq_w(self.space.add(w_list1, w_list0), w_list1)
assert self.space.eq_w(self.space.add(w_list0, w_list2), w_list2)
@@ -142,8 +152,8 @@
w = self.space.wrap
arg = w(2)
n = 3
- w_lis = W_ListObject([arg])
- w_lis3 = W_ListObject([arg]*n)
+ w_lis = W_ListObject(self.space, [arg])
+ w_lis3 = W_ListObject(self.space, [arg]*n)
w_res = self.space.mul(w_lis, w(n))
assert self.space.eq_w(w_lis3, w_res)
# commute
@@ -152,9 +162,9 @@
def test_setitem(self):
w = self.space.wrap
- w_list = W_ListObject([w(5), w(3)])
- w_exp1 = W_ListObject([w(5), w(7)])
- w_exp2 = W_ListObject([w(8), w(7)])
+ w_list = W_ListObject(self.space, [w(5), w(3)])
+ w_exp1 = W_ListObject(self.space, [w(5), w(7)])
+ w_exp2 = W_ListObject(self.space, [w(8), w(7)])
self.space.setitem(w_list, w(1), w(7))
assert self.space.eq_w(w_exp1, w_list)
self.space.setitem(w_list, w(-2), w(8))
@@ -167,7 +177,7 @@
def test_random_setitem_delitem(self):
w = self.space.wrap
s = range(39)
- w_list = W_ListObject(map(w, s))
+ w_list = W_ListObject(self.space, map(w, s))
expected = list(s)
keys = range(-len(s)-5, len(s)+5)
choices = keys + [None]*12
@@ -183,7 +193,7 @@
for key in keys:
if random.random() < 0.15:
random.shuffle(s)
- w_list = W_ListObject(map(w, s))
+ w_list = W_ListObject(self.space, map(w, s))
expected = list(s)
try:
value = expected[key]
@@ -218,11 +228,11 @@
def test_eq(self):
w = self.space.wrap
-
- w_list0 = W_ListObject([])
- w_list1 = W_ListObject([w(5), w(3), w(99)])
- w_list2 = W_ListObject([w(5), w(3), w(99)])
- w_list3 = W_ListObject([w(5), w(3), w(99), w(-1)])
+
+ w_list0 = W_ListObject(self.space, [])
+ w_list1 = W_ListObject(self.space, [w(5), w(3), w(99)])
+ w_list2 = W_ListObject(self.space, [w(5), w(3), w(99)])
+ w_list3 = W_ListObject(self.space, [w(5), w(3), w(99), w(-1)])
assert self.space.eq_w(self.space.eq(w_list0, w_list1),
self.space.w_False)
@@ -236,11 +246,11 @@
self.space.w_False)
def test_ne(self):
w = self.space.wrap
-
- w_list0 = W_ListObject([])
- w_list1 = W_ListObject([w(5), w(3), w(99)])
- w_list2 = W_ListObject([w(5), w(3), w(99)])
- w_list3 = W_ListObject([w(5), w(3), w(99), w(-1)])
+
+ w_list0 = W_ListObject(self.space, [])
+ w_list1 = W_ListObject(self.space, [w(5), w(3), w(99)])
+ w_list2 = W_ListObject(self.space, [w(5), w(3), w(99)])
+ w_list3 = W_ListObject(self.space, [w(5), w(3), w(99), w(-1)])
assert self.space.eq_w(self.space.ne(w_list0, w_list1),
self.space.w_True)
@@ -254,12 +264,12 @@
self.space.w_True)
def test_lt(self):
w = self.space.wrap
-
- w_list0 = W_ListObject([])
- w_list1 = W_ListObject([w(5), w(3), w(99)])
- w_list2 = W_ListObject([w(5), w(3), w(99)])
- w_list3 = W_ListObject([w(5), w(3), w(99), w(-1)])
- w_list4 = W_ListObject([w(5), w(3), w(9), w(-1)])
+
+ w_list0 = W_ListObject(self.space, [])
+ w_list1 = W_ListObject(self.space, [w(5), w(3), w(99)])
+ w_list2 = W_ListObject(self.space, [w(5), w(3), w(99)])
+ w_list3 = W_ListObject(self.space, [w(5), w(3), w(99), w(-1)])
+ w_list4 = W_ListObject(self.space, [w(5), w(3), w(9), w(-1)])
assert self.space.eq_w(self.space.lt(w_list0, w_list1),
self.space.w_True)
@@ -273,15 +283,15 @@
self.space.w_True)
assert self.space.eq_w(self.space.lt(w_list4, w_list3),
self.space.w_True)
-
+
def test_ge(self):
w = self.space.wrap
-
- w_list0 = W_ListObject([])
- w_list1 = W_ListObject([w(5), w(3), w(99)])
- w_list2 = W_ListObject([w(5), w(3), w(99)])
- w_list3 = W_ListObject([w(5), w(3), w(99), w(-1)])
- w_list4 = W_ListObject([w(5), w(3), w(9), w(-1)])
+
+ w_list0 = W_ListObject(self.space, [])
+ w_list1 = W_ListObject(self.space, [w(5), w(3), w(99)])
+ w_list2 = W_ListObject(self.space, [w(5), w(3), w(99)])
+ w_list3 = W_ListObject(self.space, [w(5), w(3), w(99), w(-1)])
+ w_list4 = W_ListObject(self.space, [w(5), w(3), w(9), w(-1)])
assert self.space.eq_w(self.space.ge(w_list0, w_list1),
self.space.w_False)
@@ -295,15 +305,15 @@
self.space.w_False)
assert self.space.eq_w(self.space.ge(w_list4, w_list3),
self.space.w_False)
-
+
def test_gt(self):
w = self.space.wrap
-
- w_list0 = W_ListObject([])
- w_list1 = W_ListObject([w(5), w(3), w(99)])
- w_list2 = W_ListObject([w(5), w(3), w(99)])
- w_list3 = W_ListObject([w(5), w(3), w(99), w(-1)])
- w_list4 = W_ListObject([w(5), w(3), w(9), w(-1)])
+
+ w_list0 = W_ListObject(self.space, [])
+ w_list1 = W_ListObject(self.space, [w(5), w(3), w(99)])
+ w_list2 = W_ListObject(self.space, [w(5), w(3), w(99)])
+ w_list3 = W_ListObject(self.space, [w(5), w(3), w(99), w(-1)])
+ w_list4 = W_ListObject(self.space, [w(5), w(3), w(9), w(-1)])
assert self.space.eq_w(self.space.gt(w_list0, w_list1),
self.space.w_False)
@@ -317,15 +327,15 @@
self.space.w_False)
assert self.space.eq_w(self.space.gt(w_list4, w_list3),
self.space.w_False)
-
+
def test_le(self):
w = self.space.wrap
-
- w_list0 = W_ListObject([])
- w_list1 = W_ListObject([w(5), w(3), w(99)])
- w_list2 = W_ListObject([w(5), w(3), w(99)])
- w_list3 = W_ListObject([w(5), w(3), w(99), w(-1)])
- w_list4 = W_ListObject([w(5), w(3), w(9), w(-1)])
+
+ w_list0 = W_ListObject(self.space, [])
+ w_list1 = W_ListObject(self.space, [w(5), w(3), w(99)])
+ w_list2 = W_ListObject(self.space, [w(5), w(3), w(99)])
+ w_list3 = W_ListObject(self.space, [w(5), w(3), w(99), w(-1)])
+ w_list4 = W_ListObject(self.space, [w(5), w(3), w(9), w(-1)])
assert self.space.eq_w(self.space.le(w_list0, w_list1),
self.space.w_True)
@@ -346,8 +356,62 @@
import sys
on_cpython = (option.runappdirect and
not hasattr(sys, 'pypy_translation_info'))
+ cls.w_on_cpython = cls.space.wrap(on_cpython)
- cls.w_on_cpython = cls.space.wrap(on_cpython)
+ def test_getstrategyfromlist_w(self):
+ l0 = ["a", "2", "a", True]
+ # this raised TypeError on ListStrategies
+ l1 = ["a", "2", True, "a"]
+ l2 = [1, "2", "a", "a"]
+ assert sorted(l1) == sorted(l2)
+
+ def test_notequals(self):
+ assert [1,2,3,4] != [1,2,5,4]
+
+ def test_contains(self):
+ l = []
+ assert not l.__contains__(2)
+
+ l = [1,2,3]
+ assert l.__contains__(2)
+ assert not l.__contains__("2")
+ assert l.__contains__(1.0)
+
+ l = ["1","2","3"]
+ assert l.__contains__("2")
+ assert not l.__contains__(2)
+
+ l = range(4)
+ assert l.__contains__(2)
+ assert not l.__contains__("2")
+
+ l = [1,2,"3"]
+ assert l.__contains__(2)
+ assert not l.__contains__("2")
+
+ l = range(2, 20, 3) # = [2, 5, 8, 11, 14, 17]
+ assert l.__contains__(2)
+ assert l.__contains__(5)
+ assert l.__contains__(8)
+ assert l.__contains__(11)
+ assert l.__contains__(14)
+ assert l.__contains__(17)
+ assert not l.__contains__(3)
+ assert not l.__contains__(4)
+ assert not l.__contains__(7)
+ assert not l.__contains__(13)
+ assert not l.__contains__(20)
+
+ l = range(2, -20, -3) # [2, -1, -4, -7, -10, -13, -16, -19]
+ assert l.__contains__(2)
+ assert l.__contains__(-4)
+ assert l.__contains__(-13)
+ assert l.__contains__(-16)
+ assert l.__contains__(-19)
+ assert not l.__contains__(-17)
+ assert not l.__contains__(-3)
+ assert not l.__contains__(-20)
+ assert not l.__contains__(-21)
def test_call_list(self):
assert list('') == []
@@ -385,6 +449,13 @@
l.extend([10])
assert l == range(11)
+ l = []
+ m = [1,2,3]
+ l.extend(m)
+ m[0] = 5
+ assert m == [5,2,3]
+ assert l == [1,2,3]
+
def test_extend_tuple(self):
l = l0 = [1]
l.extend((2,))
@@ -418,6 +489,10 @@
assert l is l0
assert l == [1]
+ l = ["c", "a", "d", "b"]
+ l.sort(reverse=True)
+ assert l == ["d", "c", "b", "a"]
+
def test_sort_cmp(self):
def lencmp(a,b): return cmp(len(a), len(b))
l = [ 'a', 'fiver', 'tre', '' ]
@@ -459,6 +534,11 @@
l.sort(reverse = True, key = lower)
assert l == ['C', 'b', 'a']
+ def test_sort_simple_string(self):
+ l = ["a", "d", "c", "b"]
+ l.sort()
+ assert l == ["a", "b", "c", "d"]
+
def test_getitem(self):
l = [1, 2, 3, 4, 5, 6, 9]
assert l[0] == 1
@@ -471,6 +551,21 @@
assert l[-1] == 'c'
assert l[-2] == 'b'
raises(IndexError, "l[len(l)]")
+ l = []
+ raises(IndexError, "l[1]")
+
+ def test_setitem(self):
+
+ l = []
+ raises(IndexError, "l[1] = 2")
+
+ l = [5,3]
+ l[0] = 2
+ assert l == [2,3]
+
+ l = [5,3]
+ l[0] = "2"
+ assert l == ["2",3]
def test_delitem(self):
l = [1, 2, 3, 4, 5, 6, 9]
@@ -482,7 +577,7 @@
assert l == [2, 3, 4, 6]
raises(IndexError, "del l[len(l)]")
raises(IndexError, "del l[-len(l)-1]")
-
+
l = l0 = ['a', 'b', 'c']
del l[0]
assert l == ['b', 'c']
@@ -513,7 +608,7 @@
assert l[::] == l
assert l[0::-2] == l
assert l[-1::-5] == l
-
+
l = ['']
assert l[1:] == []
assert l[1::2] == []
@@ -523,6 +618,10 @@
l.extend(['a', 'b'])
assert l[::-1] == ['b', 'a', '']
+ l = [1,2,3,4,5]
+ assert l[1:0:None] == []
+ assert l[1:0] == []
+
def test_delall(self):
l = l0 = [1,2,3]
del l[:]
@@ -564,6 +663,16 @@
l1 += bar
assert l1 == ('radd', bar, [1,2,3])
+ def test_add_lists(self):
+ l1 = [1,2,3]
+ l2 = [4,5,6]
+ l3 = l1 + l2
+ assert l3 == [1,2,3,4,5,6]
+
+ l4 = range(3)
+ l5 = l4 + l2
+ assert l5 == [0,1,2,4,5,6]
+
def test_imul(self):
l = l0 = [4,3]
l *= 2
@@ -576,7 +685,7 @@
l *= (-1)
assert l is l0
assert l == []
-
+
l = l0 = ['a', 'b']
l *= 2
assert l is l0
@@ -602,7 +711,7 @@
c = range(10)
assert c.index(0) == 0
raises(ValueError, c.index, 10)
-
+
c = list('hello world')
assert c.index('l') == 2
raises(ValueError, c.index, '!')
@@ -650,7 +759,7 @@
assert l == []
assert l is l0
- def test_ass_extended_slice(self):
+ def test_assign_extended_slice(self):
l = l0 = ['a', 'b', 'c']
l[::-1] = ['a', 'b', 'c']
assert l == ['c', 'b', 'a']
@@ -662,6 +771,41 @@
assert l == [0, 'b', 2]
assert l is l0
+ l = [1,2,3]
+ raises(ValueError, "l[0:2:2] = [1,2,3,4]")
+ raises(ValueError, "l[::2] = []")
+
+ l = range(6)
+ l[::3] = ('a', 'b')
+ assert l == ['a', 1, 2, 'b', 4, 5]
+
+ def test_setslice_with_self(self):
+ l = [1,2,3,4]
+ l[:] = l
+ assert l == [1,2,3,4]
+
+ l = [1,2,3,4]
+ l[0:2] = l
+ assert l == [1,2,3,4,3,4]
+
+ l = [1,2,3,4]
+ l[0:2] = l
+ assert l == [1,2,3,4,3,4]
+
+ l = [1,2,3,4,5,6,7,8,9,10]
+ raises(ValueError, "l[5::-1] = l")
+
+ l = [1,2,3,4,5,6,7,8,9,10]
+ raises(ValueError, "l[::2] = l")
+
+ l = [1,2,3,4,5,6,7,8,9,10]
+ l[5:] = l
+ assert l == [1,2,3,4,5,1,2,3,4,5,6,7,8,9,10]
+
+ l = [1,2,3,4,5,6]
+ l[::-1] = l
+ assert l == [6,5,4,3,2,1]
+
def test_recursive_repr(self):
l = []
assert repr(l) == '[]'
@@ -687,6 +831,10 @@
l.append(4)
assert l == range(5)
+ l = [1,2,3]
+ l.append("a")
+ assert l == [1,2,3,"a"]
+
def test_count(self):
c = list('hello')
assert c.count('l') == 2
@@ -706,6 +854,14 @@
ls.insert(0, i)
assert len(ls) == 12
+ l = []
+ l.insert(4,2)
+ assert l == [2]
+
+ l = [1,2,3]
+ l.insert(0,"a")
+ assert l == ["a", 1, 2, 3]
+
def test_pop(self):
c = list('hello world')
s = ''
@@ -719,6 +875,9 @@
l.pop()
assert l == range(9)
+ l = []
+ raises(IndexError, l.pop, 0)
+
def test_pop_custom_int(self):
class A(object):
def __init__(self, x):
@@ -733,6 +892,22 @@
assert l == range(9)
raises(TypeError, range(10).pop, 1.0)
+ def test_pop_negative(self):
+ l1 = [1,2,3,4]
+ l2 = ["1", "2", "3", "4"]
+ l3 = range(5)
+ l4 = [1, 2, 3, "4"]
+
+ raises(IndexError, l1.pop, -5)
+ raises(IndexError, l2.pop, -5)
+ raises(IndexError, l3.pop, -6)
+ raises(IndexError, l4.pop, -5)
+
+ assert l1.pop(-2) == 3
+ assert l2.pop(-2) == "3"
+ assert l3.pop(-2) == 3
+ assert l4.pop(-2) == 3
+
def test_remove(self):
c = list('hello world')
c.remove('l')
@@ -783,6 +958,20 @@
l.remove(5)
assert l[10:] == [0, 1, 2, 3, 4, 6, 7, 8, 9]
+ def test_mutate_while_contains(self):
+ class Mean(object):
+ def __init__(self, i):
+ self.i = i
+ def __eq__(self, other):
+ if self.i == 9 == other:
+ del l[0]
+ return True
+ else:
+ return False
+ l = [Mean(i) for i in range(10)]
+ assert l.__contains__(9)
+ assert not l.__contains__(2)
+
def test_mutate_while_extend(self):
# this used to segfault pypy-c (with py.test -A)
import sys
@@ -805,16 +994,36 @@
res = l.__getslice__(0, 2)
assert res == [1, 2]
+ l = []
+ assert l.__getslice__(0,2) == []
+
def test___setslice__(self):
l = [1,2,3,4]
l.__setslice__(0, 2, [5, 6])
assert l == [5, 6, 3, 4]
+ l = []
+ l.__setslice__(0,0,[3,4,5])
+ assert l == [3,4,5]
+
def test___delslice__(self):
l = [1,2,3,4]
l.__delslice__(0, 2)
assert l == [3, 4]
+ def test_unicode(self):
+ s = u"\ufffd\ufffd\ufffd"
+ assert s.encode("ascii", "replace") == "???"
+ assert s.encode("ascii", "ignore") == ""
+ l1 = [s.encode("ascii", "replace")]
+ assert l1[0] == "???"
+
+ l2 = [s.encode("ascii", "ignore")]
+ assert l2[0] == ""
+
+ l3 = [s]
+ assert l1[0].encode("ascii", "replace") == "???"
+
def test_list_from_set(self):
l = ['a']
l.__init__(set('b'))
@@ -829,6 +1038,96 @@
assert l == []
assert list(g) == []
+class AppTestForRangeLists(AppTestW_ListObject):
+
+ def setup_class(cls):
+ cls.space = gettestobjspace(**{"objspace.std.withrangelist" :
+ True})
+
+ def test_range_simple_backwards(self):
+ x = range(5,1)
+ assert x == []
+
+ def test_range_big_start(self):
+ x = range(1,10)
+ x[22:0:-1] == range(1,10)
+
+ def test_range_list_invalid_slice(self):
+ x = [1,2,3,4]
+ assert x[10:0] == []
+ assert x[10:0:None] == []
+
+ x = range(1,5)
+ assert x[10:0] == []
+ assert x[10:0:None] == []
+
+ assert x[0:22] == [1,2,3,4]
+ assert x[-1:10] == [4]
+
+ assert x[0:22:None] == [1,2,3,4]
+ assert x[-1:10:None] == [4]
+
+ def test_range_backwards(self):
+ x = range(1,10)
+ assert x[22:-10] == []
+ assert x[22:-10:-1] == [9,8,7,6,5,4,3,2,1]
+ assert x[10:3:-1] == [9,8,7,6,5]
+ assert x[10:3:-2] == [9,7,5]
+ assert x[1:5:-1] == []
+
+ def test_sort_range(self):
+ l = range(3,10,3)
+ l.sort()
+ assert l == [3, 6, 9]
+ l.sort(reverse = True)
+ assert l == [9, 6, 3]
+ l.sort(reverse = True)
+ assert l == [9, 6, 3]
+ l.sort()
+ assert l == [3, 6, 9]
+
+ def test_slice(self):
+ l = []
+ l2 = range(3)
+ l.__setslice__(0,3,l2)
+ assert l == [0,1,2]
+
+ def test_getitem(self):
+ l = range(5)
+ raises(IndexError, "l[-10]")
+
+ def test_append(self):
+ l = range(5)
+ l.append(26)
+ assert l == [0,1,2,3,4,26]
+
+ l = range(5)
+ l.append("a")
+ assert l == [0,1,2,3,4,"a"]
+
+ l = range(5)
+ l.append(5)
+ assert l == [0,1,2,3,4,5]
+
+ def test_pop(self):
+ l = range(3)
+ assert l.pop(0) == 0
+
+ def test_setitem(self):
+ l = range(3)
+ l[0] = 1
+ assert l == [1,1,2]
+
+ def test_inset(self):
+ l = range(3)
+ l.insert(1,5)
+ assert l == [0,5,1,2]
+
+ def test_reverse(self):
+ l = range(3)
+ l.reverse()
+ assert l == [2,1,0]
+
class AppTestListFastSubscr:
diff --git a/pypy/objspace/std/test/test_liststrategies.py b/pypy/objspace/std/test/test_liststrategies.py
new file mode 100644
--- /dev/null
+++ b/pypy/objspace/std/test/test_liststrategies.py
@@ -0,0 +1,419 @@
+from pypy.objspace.std.listobject import W_ListObject, EmptyListStrategy, ObjectListStrategy, IntegerListStrategy, StringListStrategy, RangeListStrategy, make_range_list
+from pypy.objspace.std import listobject
+from pypy.objspace.std.test.test_listobject import TestW_ListObject
+
+from pypy.conftest import gettestobjspace
+
+class TestW_ListStrategies(TestW_ListObject):
+
+ def test_check_strategy(self):
+ assert isinstance(W_ListObject(self.space, []).strategy, EmptyListStrategy)
+ assert isinstance(W_ListObject(self.space, [self.space.wrap(1),self.space.wrap('a')]).strategy, ObjectListStrategy)
+ assert isinstance(W_ListObject(self.space, [self.space.wrap(1),self.space.wrap(2),self.space.wrap(3)]).strategy, IntegerListStrategy)
+ assert isinstance(W_ListObject(self.space, [self.space.wrap('a'), self.space.wrap('b')]).strategy, StringListStrategy)
+
+ def test_empty_to_any(self):
+ l = W_ListObject(self.space, [])
+ assert isinstance(l.strategy, EmptyListStrategy)
+ l.append(self.space.wrap(1.))
+ assert isinstance(l.strategy, ObjectListStrategy)
+
+ l = W_ListObject(self.space, [])
+ assert isinstance(l.strategy, EmptyListStrategy)
+ l.append(self.space.wrap(1))
+ assert isinstance(l.strategy, IntegerListStrategy)
+
+ l = W_ListObject(self.space, [])
+ assert isinstance(l.strategy, EmptyListStrategy)
+ l.append(self.space.wrap('a'))
+ assert isinstance(l.strategy, StringListStrategy)
+
+ def test_int_to_any(self):
+ l = W_ListObject(self.space, [self.space.wrap(1),self.space.wrap(2),self.space.wrap(3)])
+ assert isinstance(l.strategy, IntegerListStrategy)
+ l.append(self.space.wrap(4))
+ assert isinstance(l.strategy, IntegerListStrategy)
+ l.append(self.space.wrap('a'))
+ assert isinstance(l.strategy, ObjectListStrategy)
+
+ def test_string_to_any(self):
+ l = W_ListObject(self.space, [self.space.wrap('a'),self.space.wrap('b'),self.space.wrap('c')])
+ assert isinstance(l.strategy, StringListStrategy)
+ l.append(self.space.wrap('d'))
+ assert isinstance(l.strategy, StringListStrategy)
+ l.append(self.space.wrap(3))
+ assert isinstance(l.strategy, ObjectListStrategy)
+
+ def test_setitem(self):
+ # This should work if test_listobject.py passes
+ l = W_ListObject(self.space, [self.space.wrap('a'),self.space.wrap('b'),self.space.wrap('c')])
+ assert self.space.eq_w(l.getitem(0), self.space.wrap('a'))
+ l.setitem(0, self.space.wrap('d'))
+ assert self.space.eq_w(l.getitem(0), self.space.wrap('d'))
+
+ assert isinstance(l.strategy, StringListStrategy)
+
+ # IntStrategy to ObjectStrategy
+ l = W_ListObject(self.space, [self.space.wrap(1),self.space.wrap(2),self.space.wrap(3)])
+ assert isinstance(l.strategy, IntegerListStrategy)
+ l.setitem(0, self.space.wrap('d'))
+ assert isinstance(l.strategy, ObjectListStrategy)
+
+ # StringStrategy to ObjectStrategy
+ l = W_ListObject(self.space, [self.space.wrap('a'),self.space.wrap('b'),self.space.wrap('c')])
+ assert isinstance(l.strategy, StringListStrategy)
+ l.setitem(0, self.space.wrap(2))
+ assert isinstance(l.strategy, ObjectListStrategy)
+
+ def test_insert(self):
+ # no change
+ l = W_ListObject(self.space, [self.space.wrap(1),self.space.wrap(2),self.space.wrap(3)])
+ assert isinstance(l.strategy, IntegerListStrategy)
+ l.insert(3, self.space.wrap(4))
+ assert isinstance(l.strategy, IntegerListStrategy)
+
+ # StringStrategy
+ l = W_ListObject(self.space, [self.space.wrap('a'),self.space.wrap('b'),self.space.wrap('c')])
+ assert isinstance(l.strategy, StringListStrategy)
+ l.insert(3, self.space.wrap(2))
+ assert isinstance(l.strategy, ObjectListStrategy)
+
+ # IntegerStrategy
+ l = W_ListObject(self.space, [self.space.wrap(1),self.space.wrap(2),self.space.wrap(3)])
+ assert isinstance(l.strategy, IntegerListStrategy)
+ l.insert(3, self.space.wrap('d'))
+ assert isinstance(l.strategy, ObjectListStrategy)
+
+ # EmptyStrategy
+ l = W_ListObject(self.space, [])
+ assert isinstance(l.strategy, EmptyListStrategy)
+ l.insert(0, self.space.wrap('a'))
+ assert isinstance(l.strategy, StringListStrategy)
+
+ l = W_ListObject(self.space, [])
+ assert isinstance(l.strategy, EmptyListStrategy)
+ l.insert(0, self.space.wrap(2))
+ assert isinstance(l.strategy, IntegerListStrategy)
+
+ def notest_list_empty_after_delete(self):
+ l = W_ListObject(self.space, [self.space.wrap(3)])
+ assert isinstance(l.strategy, IntegerListStrategy)
+ l.deleteitem(0)
+ assert isinstance(l.strategy, EmptyListStrategy)
+
+ l = W_ListObject(self.space, [self.space.wrap(1), self.space.wrap(2)])
+ assert isinstance(l.strategy, IntegerListStrategy)
+ l.deleteslice(0, 1, 2)
+ assert isinstance(l.strategy, EmptyListStrategy)
+
+ l = W_ListObject(self.space, [self.space.wrap(1)])
+ assert isinstance(l.strategy, IntegerListStrategy)
+ l.pop(-1)
+ assert isinstance(l.strategy, EmptyListStrategy)
+
+ def test_setslice(self):
+ l = W_ListObject(self.space, [])
+ assert isinstance(l.strategy, EmptyListStrategy)
+ l.setslice(0, 1, 2, W_ListObject(self.space, [self.space.wrap(1), self.space.wrap(2), self.space.wrap(3)]))
+ assert isinstance(l.strategy, IntegerListStrategy)
+
+ l = W_ListObject(self.space, [self.space.wrap(1), self.space.wrap(2), self.space.wrap(3)])
+ assert isinstance(l.strategy, IntegerListStrategy)
+ l.setslice(0, 1, 2, W_ListObject(self.space, [self.space.wrap(4), self.space.wrap(5), self.space.wrap(6)]))
+ assert isinstance(l.strategy, IntegerListStrategy)
+
+ l = W_ListObject(self.space, [self.space.wrap(1), self.space.wrap('b'), self.space.wrap(3)])
+ assert isinstance(l.strategy, ObjectListStrategy)
+ l.setslice(0, 1, 2, W_ListObject(self.space, [self.space.wrap(1), self.space.wrap(2), self.space.wrap(3)]))
+ assert isinstance(l.strategy, ObjectListStrategy)
+
+ l = W_ListObject(self.space, [self.space.wrap(1), self.space.wrap(2), self.space.wrap(3)])
+ assert isinstance(l.strategy, IntegerListStrategy)
+ l.setslice(0, 1, 2, W_ListObject(self.space, [self.space.wrap('a'), self.space.wrap('b'), self.space.wrap('c')]))
+ assert isinstance(l.strategy, ObjectListStrategy)
+
+ def test_setslice_List(self):
+
+ def wrapitems(items):
+ items_w = []
+ for i in items:
+ items_w.append(self.space.wrap(i))
+ return items_w
+
+ def keep_other_strategy(w_list, start, step, length, w_other):
+ other_strategy = w_other.strategy
+ w_list.setslice(start, step, length, w_other)
+ assert w_other.strategy is other_strategy
+
+ l = W_ListObject(self.space, wrapitems([1,2,3,4,5]))
+ other = W_ListObject(self.space, wrapitems(["a", "b", "c"]))
+ keep_other_strategy(l, 0, 2, other.length(), other)
+ assert l.strategy is self.space.fromcache(ObjectListStrategy)
+
+ l = W_ListObject(self.space, wrapitems([1,2,3,4,5]))
+ other = W_ListObject(self.space, wrapitems([6, 6, 6]))
+ keep_other_strategy(l, 0, 2, other.length(), other)
+ assert l.strategy is self.space.fromcache(IntegerListStrategy)
+
+ l = W_ListObject(self.space, wrapitems(["a","b","c","d","e"]))
+ other = W_ListObject(self.space, wrapitems(["a", "b", "c"]))
+ keep_other_strategy(l, 0, 2, other.length(), other)
+ assert l.strategy is self.space.fromcache(StringListStrategy)
+
+ l = W_ListObject(self.space, wrapitems(["a",3,"c",4,"e"]))
+ other = W_ListObject(self.space, wrapitems(["a", "b", "c"]))
+ keep_other_strategy(l, 0, 2, other.length(), other)
+ assert l.strategy is self.space.fromcache(ObjectListStrategy)
+
+ l = W_ListObject(self.space, wrapitems(["a",3,"c",4,"e"]))
+ other = W_ListObject(self.space, [])
+ keep_other_strategy(l, 0, 1, l.length(), other)
+ assert l.strategy is self.space.fromcache(ObjectListStrategy)
+
+ def test_empty_setslice_with_objectlist(self):
+ l = W_ListObject(self.space, [])
+ o = W_ListObject(self.space, [self.space.wrap(1), self.space.wrap("2"), self.space.wrap(3)])
+ l.setslice(0, 1, o.length(), o)
+ assert l.getitems() == o.getitems()
+ l.append(self.space.wrap(17))
+ assert l.getitems() != o.getitems()
+
+ def test_extend(self):
+ l = W_ListObject(self.space, [])
+ assert isinstance(l.strategy, EmptyListStrategy)
+ l.extend(W_ListObject(self.space, [self.space.wrap(1), self.space.wrap(2), self.space.wrap(3)]))
+ assert isinstance(l.strategy, IntegerListStrategy)
+
+ l = W_ListObject(self.space, [self.space.wrap(1), self.space.wrap(2), self.space.wrap(3)])
+ assert isinstance(l.strategy, IntegerListStrategy)
+ l.extend(W_ListObject(self.space, [self.space.wrap('a'), self.space.wrap('b'), self.space.wrap('c')]))
+ assert isinstance(l.strategy, ObjectListStrategy)
+
+ l = W_ListObject(self.space, [self.space.wrap(1), self.space.wrap(2), self.space.wrap(3)])
+ assert isinstance(l.strategy, IntegerListStrategy)
+ l.extend(W_ListObject(self.space, [self.space.wrap(4), self.space.wrap(5), self.space.wrap(6)]))
+ assert isinstance(l.strategy, IntegerListStrategy)
+
+ def test_empty_extend_with_any(self):
+ empty = W_ListObject(self.space, [])
+ assert isinstance(empty.strategy, EmptyListStrategy)
+ empty.extend(W_ListObject(self.space, [self.space.wrap(1), self.space.wrap(2), self.space.wrap(3)]))
+ assert isinstance(empty.strategy, IntegerListStrategy)
+
+ empty = W_ListObject(self.space, [])
+ assert isinstance(empty.strategy, EmptyListStrategy)
+ empty.extend(W_ListObject(self.space, [self.space.wrap("a"), self.space.wrap("b"), self.space.wrap("c")]))
+ assert isinstance(empty.strategy, StringListStrategy)
+
+ empty = W_ListObject(self.space, [])
+ assert isinstance(empty.strategy, EmptyListStrategy)
+ r = make_range_list(self.space, 1,3,7)
+ empty.extend(r)
+ assert isinstance(empty.strategy, RangeListStrategy)
+ print empty.getitem(6)
+ assert self.space.is_true(self.space.eq(empty.getitem(1), self.space.wrap(4)))
+
+ empty = W_ListObject(self.space, [])
+ assert isinstance(empty.strategy, EmptyListStrategy)
+ empty.extend(W_ListObject(self.space, [self.space.wrap(1), self.space.wrap(2), self.space.wrap(3)]))
+ assert isinstance(empty.strategy, IntegerListStrategy)
+
+ empty = W_ListObject(self.space, [])
+ assert isinstance(empty.strategy, EmptyListStrategy)
+ empty.extend(W_ListObject(self.space, []))
+ assert isinstance(empty.strategy, EmptyListStrategy)
+
+ def test_extend_other_with_empty(self):
+ l = W_ListObject(self.space, [self.space.wrap(1), self.space.wrap(2), self.space.wrap(3)])
+ assert isinstance(l.strategy, IntegerListStrategy)
+ l.extend(W_ListObject(self.space, []))
+ assert isinstance(l.strategy, IntegerListStrategy)
+
+ def test_rangelist(self):
+ l = make_range_list(self.space, 1,3,7)
+ assert isinstance(l.strategy, RangeListStrategy)
+ v = l.pop(5)
+ assert self.space.eq_w(v, self.space.wrap(16))
+ assert isinstance(l.strategy, IntegerListStrategy)
+
+ l = make_range_list(self.space, 1,3,7)
+ assert isinstance(l.strategy, RangeListStrategy)
+ v = l.pop(0)
+ assert self.space.eq_w(v, self.space.wrap(1))
+ assert isinstance(l.strategy, RangeListStrategy)
+ v = l.pop(l.length() - 1)
+ assert self.space.eq_w(v, self.space.wrap(19))
+ assert isinstance(l.strategy, RangeListStrategy)
+ v = l.pop_end()
+ assert self.space.eq_w(v, self.space.wrap(16))
+ assert isinstance(l.strategy, RangeListStrategy)
+
+ l = make_range_list(self.space, 1,3,7)
+ assert isinstance(l.strategy, RangeListStrategy)
+ l.append(self.space.wrap("string"))
+ assert isinstance(l.strategy, ObjectListStrategy)
+
+ l = make_range_list(self.space, 1,1,5)
+ assert isinstance(l.strategy, RangeListStrategy)
+ l.append(self.space.wrap(19))
+ assert isinstance(l.strategy, IntegerListStrategy)
+
+ def test_keep_range(self):
+ # simple list
+ l = make_range_list(self.space, 1,1,5)
+ assert isinstance(l.strategy, RangeListStrategy)
+ x = l.pop(0)
+ assert self.space.eq_w(x, self.space.wrap(1))
+ assert isinstance(l.strategy, RangeListStrategy)
+ l.pop(l.length()-1)
+ assert isinstance(l.strategy, RangeListStrategy)
+ l.append(self.space.wrap(5))
+ assert isinstance(l.strategy, RangeListStrategy)
+
+ # complex list
+ l = make_range_list(self.space, 1,3,5)
+ assert isinstance(l.strategy, RangeListStrategy)
+ l.append(self.space.wrap(16))
+ assert isinstance(l.strategy, RangeListStrategy)
+
+ def test_empty_range(self):
+ l = make_range_list(self.space, 0, 0, 0)
+ assert isinstance(l.strategy, EmptyListStrategy)
+
+ l = make_range_list(self.space, 1, 1, 10)
+ for i in l.getitems():
+ assert isinstance(l.strategy, RangeListStrategy)
+ l.pop(l.length()-1)
+
+ assert isinstance(l.strategy, RangeListStrategy)
+
+ def test_range_setslice(self):
+ l = make_range_list(self.space, 1, 3, 5)
+ assert isinstance(l.strategy, RangeListStrategy)
+ l.setslice(0, 1, 3, W_ListObject(self.space, [self.space.wrap(1), self.space.wrap(2), self.space.wrap(3)]))
+ assert isinstance(l.strategy, IntegerListStrategy)
+
+ def test_get_items_copy(self):
+ l1 = W_ListObject(self.space, [self.space.wrap(1), self.space.wrap(2), self.space.wrap(3)])
+ l2 = l1.getitems()
+ l2.append(self.space.wrap(4))
+ assert not l2 == l1.getitems()
+
+ l1 = W_ListObject(self.space, [self.space.wrap(1), self.space.wrap("two"), self.space.wrap(3)])
+ l2 = l1.getitems()
+ l2.append(self.space.wrap("four"))
+ assert l2 == l1.getitems()
+
+ def test_clone(self):
+ l1 = W_ListObject(self.space, [self.space.wrap(1), self.space.wrap(2), self.space.wrap(3)])
+ clone = l1.clone()
+ assert isinstance(clone.strategy, IntegerListStrategy)
+ clone.append(self.space.wrap(7))
+ assert not self.space.eq_w(l1, clone)
+
+ def test_add_does_not_use_getitems(self):
+ l1 = W_ListObject(self.space, [self.space.wrap(1), self.space.wrap(2), self.space.wrap(3)])
+ l1.getitems = None
+ l2 = W_ListObject(self.space, [self.space.wrap(1), self.space.wrap(2), self.space.wrap(3)])
+ l2.getitems = None
+ l3 = self.space.add(l1, l2)
+ l4 = W_ListObject(self.space, [self.space.wrap(1), self.space.wrap(2), self.space.wrap(3), self.space.wrap(1), self.space.wrap(2), self.space.wrap(3)])
+ assert self.space.eq_w(l3, l4)
+
+ def test_mul(self):
+ l1 = W_ListObject(self.space, [self.space.wrap(1), self.space.wrap(2), self.space.wrap(3)])
+ l2 = l1.mul(2)
+ l3 = W_ListObject(self.space, [self.space.wrap(1), self.space.wrap(2), self.space.wrap(3), self.space.wrap(1), self.space.wrap(2), self.space.wrap(3)])
+ assert self.space.eq_w(l2, l3)
+
+ l4 = make_range_list(self.space, 1, 1, 3)
+ assert self.space.eq_w(l4, l1)
+
+ l5 = l4.mul(2)
+ assert self.space.eq_w(l5, l3)
+
+ def test_mul_same_strategy_but_different_object(self):
+ l1 = W_ListObject(self.space, [self.space.wrap(1), self.space.wrap(2), self.space.wrap(3)])
+ l2 = l1.mul(1)
+ assert self.space.eq_w(l1, l2)
+ l1.setitem(0, self.space.wrap(5))
+ assert not self.space.eq_w(l1, l2)
+
+ def test_weird_rangelist_bug(self):
+ l = make_range_list(self.space, 1, 1, 3)
+ from pypy.objspace.std.listobject import getslice__List_ANY_ANY
+ # should not raise
+ assert getslice__List_ANY_ANY(self.space, l, self.space.wrap(15), self.space.wrap(2222)).strategy == self.space.fromcache(EmptyListStrategy)
+
+
+ def test_add_to_rangelist(self):
+ l1 = make_range_list(self.space, 1, 1, 3)
+ l2 = W_ListObject(self.space, [self.space.wrap(4), self.space.wrap(5)])
+ from pypy.objspace.std.listobject import add__List_List
+ l3 = add__List_List(self.space, l1, l2)
+ assert self.space.eq_w(l3, W_ListObject(self.space, [self.space.wrap(1), self.space.wrap(2), self.space.wrap(3), self.space.wrap(4), self.space.wrap(5)]))
+
+ def test_unicode(self):
+ l1 = W_ListObject(self.space, [self.space.wrap("eins"), self.space.wrap("zwei")])
+ assert isinstance(l1.strategy, StringListStrategy)
+ l2 = W_ListObject(self.space, [self.space.wrap(u"eins"), self.space.wrap(u"zwei")])
+ assert isinstance(l2.strategy, ObjectListStrategy)
+ l3 = W_ListObject(self.space, [self.space.wrap("eins"), self.space.wrap(u"zwei")])
+ assert isinstance(l3.strategy, ObjectListStrategy)
+
+ def test_listview_str(self):
+ space = self.space
+ assert space.listview_str(space.wrap("a")) is None
+ w_l = self.space.newlist([self.space.wrap('a'), self.space.wrap('b')])
+ assert space.listview_str(w_l) == ["a", "b"]
+
+ def test_string_join_uses_listview_str(self):
+ space = self.space
+ w_l = self.space.newlist([self.space.wrap('a'), self.space.wrap('b')])
+ w_l.getitems = None
+ assert space.str_w(space.call_method(space.wrap("c"), "join", w_l)) == "acb"
+
+ def test_string_join_returns_same_instance(self):
+ space = self.space
+ w_text = space.wrap("text")
+ w_l = self.space.newlist([w_text])
+ w_l.getitems = None
+ assert space.is_w(space.call_method(space.wrap(" -- "), "join", w_l), w_text)
+
+ def test_newlist_str(self):
+ space = self.space
+ l = ['a', 'b']
+ w_l = self.space.newlist_str(l)
+ assert isinstance(w_l.strategy, StringListStrategy)
+ assert space.listview_str(w_l) is l
+
+ def test_string_uses_newlist_str(self):
+ space = self.space
+ w_s = space.wrap("a b c")
+ space.newlist = None
+ try:
+ w_l = space.call_method(w_s, "split")
+ w_l2 = space.call_method(w_s, "split", space.wrap(" "))
+ finally:
+ del space.newlist
+ assert space.listview_str(w_l) == ["a", "b", "c"]
+ assert space.listview_str(w_l2) == ["a", "b", "c"]
+
+ def test_pop_without_argument_is_fast(self):
+ space = self.space
+ w_l = W_ListObject(space, [space.wrap(1), space.wrap(2), space.wrap(3)])
+ w_l.pop = None
+ w_res = listobject.list_pop__List_ANY(space, w_l, space.w_None) # does not crash
+ assert space.unwrap(w_res) == 3
+
+
+class TestW_ListStrategiesDisabled:
+ def setup_class(cls):
+ cls.space = gettestobjspace(**{"objspace.std.withliststrategies" :
+ False})
+
+ def test_check_strategy(self):
+ assert isinstance(W_ListObject(self.space, []).strategy, ObjectListStrategy)
+ assert isinstance(W_ListObject(self.space, [self.space.wrap(1),self.space.wrap('a')]).strategy, ObjectListStrategy)
+ assert isinstance(W_ListObject(self.space, [self.space.wrap(1),self.space.wrap(2),self.space.wrap(3)]).strategy, ObjectListStrategy)
+ assert isinstance(W_ListObject(self.space, [self.space.wrap('a'), self.space.wrap('b')]).strategy, ObjectListStrategy)
diff --git a/pypy/objspace/std/test/test_obj.py b/pypy/objspace/std/test/test_obj.py
--- a/pypy/objspace/std/test/test_obj.py
+++ b/pypy/objspace/std/test/test_obj.py
@@ -4,12 +4,24 @@
class AppTestObject:
def setup_class(cls):
+ from pypy.interpreter import gateway
import sys
+
cpython_behavior = (not option.runappdirect
or not hasattr(sys, 'pypy_translation_info'))
- cls.w_cpython_behavior = cls.space.wrap(cpython_behavior)
- cls.w_cpython_version = cls.space.wrap(tuple(sys.version_info))
More information about the pypy-commit
mailing list