[pypy-commit] pypy win64-stage1: Merge with default
ctismer
noreply at buildbot.pypy.org
Tue Mar 27 05:09:09 CEST 2012
Author: Christian Tismer <tismer at stackless.com>
Branch: win64-stage1
Changeset: r54021:ceb003ff6d6f
Date: 2012-03-27 03:33 +0100
http://bitbucket.org/pypy/pypy/changeset/ceb003ff6d6f/
Log: Merge with default
diff --git a/lib-python/modified-2.7/test/test_set.py b/lib-python/modified-2.7/test/test_set.py
--- a/lib-python/modified-2.7/test/test_set.py
+++ b/lib-python/modified-2.7/test/test_set.py
@@ -1568,7 +1568,7 @@
for meth in (s.union, s.intersection, s.difference, s.symmetric_difference, s.isdisjoint):
for g in (G, I, Ig, L, R):
expected = meth(data)
- actual = meth(G(data))
+ actual = meth(g(data))
if isinstance(expected, bool):
self.assertEqual(actual, expected)
else:
diff --git a/pypy/interpreter/astcompiler/test/test_astbuilder.py b/pypy/interpreter/astcompiler/test/test_astbuilder.py
--- a/pypy/interpreter/astcompiler/test/test_astbuilder.py
+++ b/pypy/interpreter/astcompiler/test/test_astbuilder.py
@@ -10,16 +10,6 @@
from pypy.interpreter.astcompiler import ast, consts
-try:
- all
-except NameError:
- def all(iterable):
- for x in iterable:
- if not x:
- return False
- return True
-
-
class TestAstBuilder:
def setup_class(cls):
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
@@ -16,7 +16,7 @@
a[i][i] = 1
return a
-def sum(a,axis=None):
+def sum(a,axis=None, out=None):
'''sum(a, axis=None)
Sum of array elements over a given axis.
@@ -43,17 +43,17 @@
# TODO: add to doc (once it's implemented): cumsum : Cumulative sum of array elements.
if not hasattr(a, "sum"):
a = _numpypy.array(a)
- return a.sum(axis)
+ return a.sum(axis=axis, out=out)
-def min(a, axis=None):
+def min(a, axis=None, out=None):
if not hasattr(a, "min"):
a = _numpypy.array(a)
- return a.min(axis)
+ return a.min(axis=axis, out=out)
-def max(a, axis=None):
+def max(a, axis=None, out=None):
if not hasattr(a, "max"):
a = _numpypy.array(a)
- return a.max(axis)
+ return a.max(axis=axis, out=out)
def arange(start, stop=None, step=1, dtype=None):
'''arange([start], stop[, step], dtype=None)
diff --git a/pypy/module/micronumpy/interp_boxes.py b/pypy/module/micronumpy/interp_boxes.py
--- a/pypy/module/micronumpy/interp_boxes.py
+++ b/pypy/module/micronumpy/interp_boxes.py
@@ -62,21 +62,24 @@
return space.wrap(dtype.itemtype.bool(self))
def _binop_impl(ufunc_name):
- def impl(self, space, w_other):
+ def impl(self, space, w_other, w_out=None):
from pypy.module.micronumpy import interp_ufuncs
- return getattr(interp_ufuncs.get(space), ufunc_name).call(space, [self, w_other])
+ return getattr(interp_ufuncs.get(space), ufunc_name).call(space,
+ [self, w_other, w_out])
return func_with_new_name(impl, "binop_%s_impl" % ufunc_name)
def _binop_right_impl(ufunc_name):
- def impl(self, space, w_other):
+ def impl(self, space, w_other, w_out=None):
from pypy.module.micronumpy import interp_ufuncs
- return getattr(interp_ufuncs.get(space), ufunc_name).call(space, [w_other, self])
+ return getattr(interp_ufuncs.get(space), ufunc_name).call(space,
+ [w_other, self, w_out])
return func_with_new_name(impl, "binop_right_%s_impl" % ufunc_name)
def _unaryop_impl(ufunc_name):
- def impl(self, space):
+ def impl(self, space, w_out=None):
from pypy.module.micronumpy import interp_ufuncs
- return getattr(interp_ufuncs.get(space), ufunc_name).call(space, [self])
+ return getattr(interp_ufuncs.get(space), ufunc_name).call(space,
+ [self, w_out])
return func_with_new_name(impl, "unaryop_%s_impl" % ufunc_name)
descr_add = _binop_impl("add")
diff --git a/pypy/module/micronumpy/interp_iter.py b/pypy/module/micronumpy/interp_iter.py
--- a/pypy/module/micronumpy/interp_iter.py
+++ b/pypy/module/micronumpy/interp_iter.py
@@ -269,7 +269,7 @@
def apply_transformations(self, arr, transformations):
v = BaseIterator.apply_transformations(self, arr, transformations)
- if len(arr.shape) == 1:
+ if len(arr.shape) == 1 and len(v.res_shape) == 1:
return OneDimIterator(self.offset, self.strides[0],
self.res_shape[0])
return v
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
@@ -83,8 +83,9 @@
return space.wrap(W_NDimArray(shape[:], dtype=dtype))
def _unaryop_impl(ufunc_name):
- def impl(self, space):
- return getattr(interp_ufuncs.get(space), ufunc_name).call(space, [self])
+ def impl(self, space, w_out=None):
+ return getattr(interp_ufuncs.get(space), ufunc_name).call(space,
+ [self, w_out])
return func_with_new_name(impl, "unaryop_%s_impl" % ufunc_name)
descr_pos = _unaryop_impl("positive")
@@ -93,8 +94,9 @@
descr_invert = _unaryop_impl("invert")
def _binop_impl(ufunc_name):
- def impl(self, space, w_other):
- return getattr(interp_ufuncs.get(space), ufunc_name).call(space, [self, w_other])
+ def impl(self, space, w_other, w_out=None):
+ return getattr(interp_ufuncs.get(space), ufunc_name).call(space,
+ [self, w_other, w_out])
return func_with_new_name(impl, "binop_%s_impl" % ufunc_name)
descr_add = _binop_impl("add")
@@ -124,12 +126,12 @@
return space.newtuple([w_quotient, w_remainder])
def _binop_right_impl(ufunc_name):
- def impl(self, space, w_other):
+ def impl(self, space, w_other, w_out=None):
w_other = scalar_w(space,
interp_ufuncs.find_dtype_for_scalar(space, w_other, self.find_dtype()),
w_other
)
- return getattr(interp_ufuncs.get(space), ufunc_name).call(space, [w_other, self])
+ return getattr(interp_ufuncs.get(space), ufunc_name).call(space, [w_other, self, w_out])
return func_with_new_name(impl, "binop_right_%s_impl" % ufunc_name)
descr_radd = _binop_right_impl("add")
@@ -152,13 +154,21 @@
return space.newtuple([w_quotient, w_remainder])
def _reduce_ufunc_impl(ufunc_name, promote_to_largest=False):
- def impl(self, space, w_axis=None):
+ def impl(self, space, w_axis=None, w_out=None):
if space.is_w(w_axis, space.w_None):
axis = -1
else:
axis = space.int_w(w_axis)
+ if space.is_w(w_out, space.w_None) or not w_out:
+ out = None
+ elif not isinstance(w_out, BaseArray):
+ raise OperationError(space.w_TypeError, space.wrap(
+ 'output must be an array'))
+ else:
+ out = w_out
return getattr(interp_ufuncs.get(space), ufunc_name).reduce(space,
- self, True, promote_to_largest, axis)
+ self, True, promote_to_largest, axis,
+ False, out)
return func_with_new_name(impl, "reduce_%s_impl" % ufunc_name)
descr_sum = _reduce_ufunc_impl("add")
@@ -213,6 +223,7 @@
def descr_dot(self, space, w_other):
other = convert_to_array(space, w_other)
if isinstance(other, Scalar):
+ #Note: w_out is not modified, this is numpy compliant.
return self.descr_mul(space, other)
elif len(self.shape) < 2 and len(other.shape) < 2:
w_res = self.descr_mul(space, other)
@@ -514,14 +525,14 @@
)
return w_result
- def descr_mean(self, space, w_axis=None):
+ def descr_mean(self, space, w_axis=None, w_out=None):
if space.is_w(w_axis, space.w_None):
w_axis = space.wrap(-1)
w_denom = space.wrap(support.product(self.shape))
else:
dim = space.int_w(w_axis)
w_denom = space.wrap(self.shape[dim])
- return space.div(self.descr_sum_promote(space, w_axis), w_denom)
+ return space.div(self.descr_sum_promote(space, w_axis, w_out), w_denom)
def descr_var(self, space, w_axis=None):
return get_appbridge_cache(space).call_method(space, '_var', self,
@@ -714,11 +725,12 @@
"""
Class for representing virtual arrays, such as binary ops or ufuncs
"""
- def __init__(self, name, shape, res_dtype):
+ def __init__(self, name, shape, res_dtype, out_arg=None):
BaseArray.__init__(self, shape)
self.forced_result = None
self.res_dtype = res_dtype
self.name = name
+ self.res = out_arg
self.size = support.product(self.shape) * res_dtype.get_size()
def _del_sources(self):
@@ -727,13 +739,18 @@
raise NotImplementedError
def compute(self):
- ra = ResultArray(self, self.shape, self.res_dtype)
+ ra = ResultArray(self, self.shape, self.res_dtype, self.res)
loop.compute(ra)
+ if self.res:
+ broadcast_dims = len(self.res.shape) - len(self.shape)
+ chunks = [Chunk(0,0,0,0)] * broadcast_dims + \
+ [Chunk(0, i, 1, i) for i in self.shape]
+ return Chunks(chunks).apply(self.res)
return ra.left
def force_if_needed(self):
if self.forced_result is None:
- self.forced_result = self.compute()
+ self.forced_result = self.compute().get_concrete()
self._del_sources()
def get_concrete(self):
@@ -773,8 +790,9 @@
class Call1(VirtualArray):
- def __init__(self, ufunc, name, shape, calc_dtype, res_dtype, values):
- VirtualArray.__init__(self, name, shape, res_dtype)
+ def __init__(self, ufunc, name, shape, calc_dtype, res_dtype, values,
+ out_arg=None):
+ VirtualArray.__init__(self, name, shape, res_dtype, out_arg)
self.values = values
self.size = values.size
self.ufunc = ufunc
@@ -786,6 +804,12 @@
def create_sig(self):
if self.forced_result is not None:
return self.forced_result.create_sig()
+ if self.shape != self.values.shape:
+ #This happens if out arg is used
+ return signature.BroadcastUfunc(self.ufunc, self.name,
+ self.calc_dtype,
+ self.values.create_sig(),
+ self.res.create_sig())
return signature.Call1(self.ufunc, self.name, self.calc_dtype,
self.values.create_sig())
@@ -793,8 +817,9 @@
"""
Intermediate class for performing binary operations.
"""
- def __init__(self, ufunc, name, shape, calc_dtype, res_dtype, left, right):
- VirtualArray.__init__(self, name, shape, res_dtype)
+ def __init__(self, ufunc, name, shape, calc_dtype, res_dtype, left, right,
+ out_arg=None):
+ VirtualArray.__init__(self, name, shape, res_dtype, out_arg)
self.ufunc = ufunc
self.left = left
self.right = right
@@ -832,8 +857,13 @@
Call2.__init__(self, None, 'assign', shape, dtype, dtype, res, child)
def create_sig(self):
- return signature.ResultSignature(self.res_dtype, self.left.create_sig(),
- self.right.create_sig())
+ if self.left.shape != self.right.shape:
+ sig = signature.BroadcastResultSignature(self.res_dtype,
+ self.left.create_sig(), self.right.create_sig())
+ else:
+ sig = signature.ResultSignature(self.res_dtype,
+ self.left.create_sig(), self.right.create_sig())
+ return sig
class ToStringArray(Call1):
def __init__(self, child):
@@ -842,9 +872,9 @@
self.s = StringBuilder(child.size * self.item_size)
Call1.__init__(self, None, 'tostring', child.shape, dtype, dtype,
child)
- self.res = W_NDimArray([1], dtype, 'C')
- self.res_casted = rffi.cast(rffi.CArrayPtr(lltype.Char),
- self.res.storage)
+ self.res_str = W_NDimArray([1], dtype, order='C')
+ self.res_str_casted = rffi.cast(rffi.CArrayPtr(lltype.Char),
+ self.res_str.storage)
def create_sig(self):
return signature.ToStringSignature(self.calc_dtype,
@@ -950,7 +980,7 @@
def setitem(self, item, value):
self.invalidated()
- self.dtype.setitem(self, item, value)
+ self.dtype.setitem(self, item, value.convert_to(self.dtype))
def calc_strides(self, shape):
dtype = self.find_dtype()
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
@@ -28,26 +28,38 @@
return self.identity
def descr_call(self, space, __args__):
+ from interp_numarray import BaseArray
args_w, kwds_w = __args__.unpack()
# it occurs to me that we don't support any datatypes that
# require casting, change it later when we do
kwds_w.pop('casting', None)
w_subok = kwds_w.pop('subok', None)
w_out = kwds_w.pop('out', space.w_None)
- if ((w_subok is not None and space.is_true(w_subok)) or
- not space.is_w(w_out, space.w_None)):
+ # Setup a default value for out
+ if space.is_w(w_out, space.w_None):
+ out = None
+ else:
+ out = w_out
+ if (w_subok is not None and space.is_true(w_subok)):
raise OperationError(space.w_NotImplementedError,
space.wrap("parameters unsupported"))
if kwds_w or len(args_w) < self.argcount:
raise OperationError(space.w_ValueError,
space.wrap("invalid number of arguments")
)
- elif len(args_w) > self.argcount:
- # The extra arguments should actually be the output array, but we
- # don't support that yet.
+ elif (len(args_w) > self.argcount and out is not None) or \
+ (len(args_w) > self.argcount + 1):
raise OperationError(space.w_TypeError,
space.wrap("invalid number of arguments")
)
+ # Override the default out value, if it has been provided in w_wargs
+ if len(args_w) > self.argcount:
+ out = args_w[-1]
+ else:
+ args_w = args_w[:] + [out]
+ if out is not None and not isinstance(out, BaseArray):
+ raise OperationError(space.w_TypeError, space.wrap(
+ 'output must be an array'))
return self.call(space, args_w)
@unwrap_spec(skipna=bool, keepdims=bool)
@@ -105,28 +117,33 @@
array([[ 1, 5],
[ 9, 13]])
"""
- if not space.is_w(w_out, space.w_None):
- raise OperationError(space.w_NotImplementedError, space.wrap(
- "out not supported"))
+ from pypy.module.micronumpy.interp_numarray import BaseArray
if w_axis is None:
axis = 0
elif space.is_w(w_axis, space.w_None):
axis = -1
else:
axis = space.int_w(w_axis)
- return self.reduce(space, w_obj, False, False, axis, keepdims)
+ if space.is_w(w_out, space.w_None):
+ out = None
+ elif not isinstance(w_out, BaseArray):
+ raise OperationError(space.w_TypeError, space.wrap(
+ 'output must be an array'))
+ else:
+ out = w_out
+ return self.reduce(space, w_obj, False, False, axis, keepdims, out)
- def reduce(self, space, w_obj, multidim, promote_to_largest, dim,
- keepdims=False):
+ def reduce(self, space, w_obj, multidim, promote_to_largest, axis,
+ keepdims=False, out=None):
from pypy.module.micronumpy.interp_numarray import convert_to_array, \
- Scalar, ReduceArray
+ Scalar, ReduceArray, W_NDimArray
if self.argcount != 2:
raise OperationError(space.w_ValueError, space.wrap("reduce only "
"supported for binary functions"))
assert isinstance(self, W_Ufunc2)
obj = convert_to_array(space, w_obj)
- if dim >= len(obj.shape):
- raise OperationError(space.w_ValueError, space.wrap("axis(=%d) out of bounds" % dim))
+ if axis >= len(obj.shape):
+ raise OperationError(space.w_ValueError, space.wrap("axis(=%d) out of bounds" % axis))
if isinstance(obj, Scalar):
raise OperationError(space.w_TypeError, space.wrap("cannot reduce "
"on a scalar"))
@@ -144,21 +161,55 @@
if self.identity is None and size == 0:
raise operationerrfmt(space.w_ValueError, "zero-size array to "
"%s.reduce without identity", self.name)
- if shapelen > 1 and dim >= 0:
- return self.do_axis_reduce(obj, dtype, dim, keepdims)
- arr = ReduceArray(self.func, self.name, self.identity, obj, dtype)
- return loop.compute(arr)
+ if shapelen > 1 and axis >= 0:
+ if keepdims:
+ shape = obj.shape[:axis] + [1] + obj.shape[axis + 1:]
+ else:
+ shape = obj.shape[:axis] + obj.shape[axis + 1:]
+ if out:
+ #Test for shape agreement
+ if len(out.shape) > len(shape):
+ raise operationerrfmt(space.w_ValueError,
+ 'output parameter for reduction operation %s' +
+ ' has too many dimensions', self.name)
+ elif len(out.shape) < len(shape):
+ raise operationerrfmt(space.w_ValueError,
+ 'output parameter for reduction operation %s' +
+ ' does not have enough dimensions', self.name)
+ elif out.shape != shape:
+ raise operationerrfmt(space.w_ValueError,
+ 'output parameter shape mismatch, expecting [%s]' +
+ ' , got [%s]',
+ ",".join([str(x) for x in shape]),
+ ",".join([str(x) for x in out.shape]),
+ )
+ #Test for dtype agreement, perhaps create an itermediate
+ #if out.dtype != dtype:
+ # raise OperationError(space.w_TypeError, space.wrap(
+ # "mismatched dtypes"))
+ return self.do_axis_reduce(obj, out.find_dtype(), axis, out)
+ else:
+ result = W_NDimArray(shape, dtype)
+ return self.do_axis_reduce(obj, dtype, axis, result)
+ if out:
+ if len(out.shape)>0:
+ raise operationerrfmt(space.w_ValueError, "output parameter "
+ "for reduction operation %s has too many"
+ " dimensions",self.name)
+ arr = ReduceArray(self.func, self.name, self.identity, obj,
+ out.find_dtype())
+ val = loop.compute(arr)
+ assert isinstance(out, Scalar)
+ out.value = val
+ else:
+ arr = ReduceArray(self.func, self.name, self.identity, obj, dtype)
+ val = loop.compute(arr)
+ return val
- def do_axis_reduce(self, obj, dtype, dim, keepdims):
- from pypy.module.micronumpy.interp_numarray import AxisReduce,\
- W_NDimArray
- if keepdims:
- shape = obj.shape[:dim] + [1] + obj.shape[dim + 1:]
- else:
- shape = obj.shape[:dim] + obj.shape[dim + 1:]
- result = W_NDimArray(shape, dtype)
+ def do_axis_reduce(self, obj, dtype, axis, result):
+ from pypy.module.micronumpy.interp_numarray import AxisReduce
arr = AxisReduce(self.func, self.name, self.identity, obj.shape, dtype,
- result, obj, dim)
+ result, obj, axis)
loop.compute(arr)
return arr.left
@@ -176,24 +227,55 @@
self.bool_result = bool_result
def call(self, space, args_w):
- from pypy.module.micronumpy.interp_numarray import (Call1,
- convert_to_array, Scalar)
-
- [w_obj] = args_w
+ from pypy.module.micronumpy.interp_numarray import (Call1, BaseArray,
+ convert_to_array, Scalar, shape_agreement)
+ if len(args_w)<2:
+ [w_obj] = args_w
+ out = None
+ else:
+ [w_obj, out] = args_w
+ if space.is_w(out, space.w_None):
+ out = None
w_obj = convert_to_array(space, w_obj)
calc_dtype = find_unaryop_result_dtype(space,
w_obj.find_dtype(),
promote_to_float=self.promote_to_float,
promote_bools=self.promote_bools)
- if self.bool_result:
+ if out:
+ if not isinstance(out, BaseArray):
+ raise OperationError(space.w_TypeError, space.wrap(
+ 'output must be an array'))
+ res_dtype = out.find_dtype()
+ elif self.bool_result:
res_dtype = interp_dtype.get_dtype_cache(space).w_booldtype
else:
res_dtype = calc_dtype
if isinstance(w_obj, Scalar):
- return space.wrap(self.func(calc_dtype, w_obj.value.convert_to(calc_dtype)))
-
- w_res = Call1(self.func, self.name, w_obj.shape, calc_dtype, res_dtype,
- w_obj)
+ arr = self.func(calc_dtype, w_obj.value.convert_to(calc_dtype))
+ if isinstance(out,Scalar):
+ out.value=arr
+ elif isinstance(out, BaseArray):
+ out.fill(space, arr)
+ else:
+ out = arr
+ return space.wrap(out)
+ if out:
+ assert isinstance(out, BaseArray) # For translation
+ broadcast_shape = shape_agreement(space, w_obj.shape, out.shape)
+ if not broadcast_shape or broadcast_shape != out.shape:
+ raise operationerrfmt(space.w_ValueError,
+ 'output parameter shape mismatch, could not broadcast [%s]' +
+ ' to [%s]',
+ ",".join([str(x) for x in w_obj.shape]),
+ ",".join([str(x) for x in out.shape]),
+ )
+ w_res = Call1(self.func, self.name, out.shape, calc_dtype,
+ res_dtype, w_obj, out)
+ #Force it immediately
+ w_res.get_concrete()
+ else:
+ w_res = Call1(self.func, self.name, w_obj.shape, calc_dtype,
+ res_dtype, w_obj)
w_obj.add_invalidates(w_res)
return w_res
@@ -212,32 +294,61 @@
def call(self, space, args_w):
from pypy.module.micronumpy.interp_numarray import (Call2,
- convert_to_array, Scalar, shape_agreement)
-
- [w_lhs, w_rhs] = args_w
+ convert_to_array, Scalar, shape_agreement, BaseArray)
+ if len(args_w)>2:
+ [w_lhs, w_rhs, w_out] = args_w
+ else:
+ [w_lhs, w_rhs] = args_w
+ w_out = None
w_lhs = convert_to_array(space, w_lhs)
w_rhs = convert_to_array(space, w_rhs)
- calc_dtype = find_binop_result_dtype(space,
- w_lhs.find_dtype(), w_rhs.find_dtype(),
- int_only=self.int_only,
- promote_to_float=self.promote_to_float,
- promote_bools=self.promote_bools,
- )
+ if space.is_w(w_out, space.w_None) or w_out is None:
+ out = None
+ calc_dtype = find_binop_result_dtype(space,
+ w_lhs.find_dtype(), w_rhs.find_dtype(),
+ int_only=self.int_only,
+ promote_to_float=self.promote_to_float,
+ promote_bools=self.promote_bools,
+ )
+ elif not isinstance(w_out, BaseArray):
+ raise OperationError(space.w_TypeError, space.wrap(
+ 'output must be an array'))
+ else:
+ out = w_out
+ calc_dtype = out.find_dtype()
if self.comparison_func:
res_dtype = interp_dtype.get_dtype_cache(space).w_booldtype
else:
res_dtype = calc_dtype
if isinstance(w_lhs, Scalar) and isinstance(w_rhs, Scalar):
- return space.wrap(self.func(calc_dtype,
+ arr = self.func(calc_dtype,
w_lhs.value.convert_to(calc_dtype),
w_rhs.value.convert_to(calc_dtype)
- ))
+ )
+ if isinstance(out,Scalar):
+ out.value=arr
+ elif isinstance(out, BaseArray):
+ out.fill(space, arr)
+ else:
+ out = arr
+ return space.wrap(out)
new_shape = shape_agreement(space, w_lhs.shape, w_rhs.shape)
+ # Test correctness of out.shape
+ if out and out.shape != shape_agreement(space, new_shape, out.shape):
+ raise operationerrfmt(space.w_ValueError,
+ 'output parameter shape mismatch, could not broadcast [%s]' +
+ ' to [%s]',
+ ",".join([str(x) for x in new_shape]),
+ ",".join([str(x) for x in out.shape]),
+ )
w_res = Call2(self.func, self.name,
new_shape, calc_dtype,
- res_dtype, w_lhs, w_rhs)
+ res_dtype, w_lhs, w_rhs, out)
w_lhs.add_invalidates(w_res)
w_rhs.add_invalidates(w_res)
+ if out:
+ #out.add_invalidates(w_res) #causes a recursion loop
+ w_res.get_concrete()
return w_res
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
@@ -216,13 +216,14 @@
return self.child.eval(frame, arr.child)
class Call1(Signature):
- _immutable_fields_ = ['unfunc', 'name', 'child', 'dtype']
+ _immutable_fields_ = ['unfunc', 'name', 'child', 'res', 'dtype']
- def __init__(self, func, name, dtype, child):
+ def __init__(self, func, name, dtype, child, res=None):
self.unfunc = func
self.child = child
self.name = name
self.dtype = dtype
+ self.res = res
def hash(self):
return compute_hash(self.name) ^ intmask(self.child.hash() << 1)
@@ -256,6 +257,29 @@
v = self.child.eval(frame, arr.values).convert_to(arr.calc_dtype)
return self.unfunc(arr.calc_dtype, v)
+
+class BroadcastUfunc(Call1):
+ def _invent_numbering(self, cache, allnumbers):
+ self.res._invent_numbering(cache, allnumbers)
+ self.child._invent_numbering(new_cache(), allnumbers)
+
+ def debug_repr(self):
+ return 'BroadcastUfunc(%s, %s)' % (self.name, self.child.debug_repr())
+
+ def _create_iter(self, iterlist, arraylist, arr, transforms):
+ from pypy.module.micronumpy.interp_numarray import Call1
+
+ assert isinstance(arr, Call1)
+ vtransforms = transforms + [BroadcastTransform(arr.values.shape)]
+ self.child._create_iter(iterlist, arraylist, arr.values, vtransforms)
+ self.res._create_iter(iterlist, arraylist, arr.res, transforms)
+
+ def eval(self, frame, arr):
+ from pypy.module.micronumpy.interp_numarray import Call1
+ assert isinstance(arr, Call1)
+ v = self.child.eval(frame, arr.values).convert_to(arr.calc_dtype)
+ return self.unfunc(arr.calc_dtype, v)
+
class Call2(Signature):
_immutable_fields_ = ['binfunc', 'name', 'calc_dtype', 'left', 'right']
@@ -316,7 +340,17 @@
assert isinstance(arr, ResultArray)
offset = frame.get_final_iter().offset
- arr.left.setitem(offset, self.right.eval(frame, arr.right))
+ val = self.right.eval(frame, arr.right)
+ arr.left.setitem(offset, val)
+
+class BroadcastResultSignature(ResultSignature):
+ def _create_iter(self, iterlist, arraylist, arr, transforms):
+ from pypy.module.micronumpy.interp_numarray import ResultArray
+
+ assert isinstance(arr, ResultArray)
+ rtransforms = transforms + [BroadcastTransform(arr.left.shape)]
+ self.left._create_iter(iterlist, arraylist, arr.left, transforms)
+ self.right._create_iter(iterlist, arraylist, arr.right, rtransforms)
class ToStringSignature(Call1):
def __init__(self, dtype, child):
@@ -327,10 +361,10 @@
from pypy.module.micronumpy.interp_numarray import ToStringArray
assert isinstance(arr, ToStringArray)
- arr.res.setitem(0, self.child.eval(frame, arr.values).convert_to(
+ arr.res_str.setitem(0, self.child.eval(frame, arr.values).convert_to(
self.dtype))
for i in range(arr.item_size):
- arr.s.append(arr.res_casted[i])
+ arr.s.append(arr.res_str_casted[i])
class BroadcastLeft(Call2):
def _invent_numbering(self, cache, allnumbers):
@@ -455,6 +489,5 @@
cur = arr.left.getitem(iterator.offset)
value = self.binfunc(self.calc_dtype, cur, v)
arr.left.setitem(iterator.offset, value)
-
def debug_repr(self):
return 'AxisReduceSig(%s, %s)' % (self.name, self.right.debug_repr())
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
@@ -995,6 +995,10 @@
assert a.sum() == 5
raises(TypeError, 'a.sum(2, 3)')
+ d = array(0.)
+ b = a.sum(out=d)
+ assert b == d
+ assert isinstance(b, float)
def test_reduce_nd(self):
from numpypy import arange, array, multiply
@@ -1495,8 +1499,6 @@
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
diff --git a/pypy/module/micronumpy/test/test_outarg.py b/pypy/module/micronumpy/test/test_outarg.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/micronumpy/test/test_outarg.py
@@ -0,0 +1,126 @@
+import py
+from pypy.module.micronumpy.test.test_base import BaseNumpyAppTest
+
+class AppTestOutArg(BaseNumpyAppTest):
+ def test_reduce_out(self):
+ from numpypy import arange, zeros, array
+ a = arange(15).reshape(5, 3)
+ b = arange(12).reshape(4,3)
+ c = a.sum(0, out=b[1])
+ assert (c == [30, 35, 40]).all()
+ assert (c == b[1]).all()
+ raises(ValueError, 'a.prod(0, out=arange(10))')
+ a=arange(12).reshape(3,2,2)
+ raises(ValueError, 'a.sum(0, out=arange(12).reshape(3,2,2))')
+ raises(ValueError, 'a.sum(0, out=arange(3))')
+ c = array([-1, 0, 1]).sum(out=zeros([], dtype=bool))
+ #You could argue that this should product False, but
+ # that would require an itermediate result. Cpython numpy
+ # gives True.
+ assert c == True
+ a = array([[-1, 0, 1], [1, 0, -1]])
+ c = a.sum(0, out=zeros((3,), dtype=bool))
+ assert (c == [True, False, True]).all()
+ c = a.sum(1, out=zeros((2,), dtype=bool))
+ assert (c == [True, True]).all()
+
+ def test_reduce_intermediary(self):
+ from numpypy import arange, array
+ a = arange(15).reshape(5, 3)
+ b = array(range(3), dtype=bool)
+ c = a.prod(0, out=b)
+ assert(b == [False, True, True]).all()
+
+ def test_ufunc_out(self):
+ from _numpypy import array, negative, zeros, sin
+ from math import sin as msin
+ a = array([[1, 2], [3, 4]])
+ c = zeros((2,2,2))
+ b = negative(a + a, out=c[1])
+ #test for view, and also test that forcing out also forces b
+ assert (c[:, :, 1] == [[0, 0], [-4, -8]]).all()
+ assert (b == [[-2, -4], [-6, -8]]).all()
+ #Test broadcast, type promotion
+ b = negative(3, out=a)
+ assert (a == -3).all()
+ c = zeros((2, 2), dtype=float)
+ b = negative(3, out=c)
+ assert b.dtype.kind == c.dtype.kind
+ assert b.shape == c.shape
+ a = array([1, 2])
+ b = sin(a, out=c)
+ assert(c == [[msin(1), msin(2)]] * 2).all()
+ b = sin(a, out=c+c)
+ assert (c == b).all()
+
+ #Test shape agreement
+ a = zeros((3,4))
+ b = zeros((3,5))
+ raises(ValueError, 'negative(a, out=b)')
+ b = zeros((1,4))
+ raises(ValueError, 'negative(a, out=b)')
+
+ def test_binfunc_out(self):
+ from _numpypy import array, add
+ a = array([[1, 2], [3, 4]])
+ out = array([[1, 2], [3, 4]])
+ c = add(a, a, out=out)
+ assert (c == out).all()
+ assert c.shape == a.shape
+ assert c.dtype is a.dtype
+ c[0,0] = 100
+ assert out[0, 0] == 100
+ out[:] = 100
+ raises(ValueError, 'c = add(a, a, out=out[1])')
+ c = add(a[0], a[1], out=out[1])
+ assert (c == out[1]).all()
+ assert (c == [4, 6]).all()
+ assert (out[0] == 100).all()
+ c = add(a[0], a[1], out=out)
+ assert (c == out[1]).all()
+ assert (c == out[0]).all()
+ out = array(16, dtype=int)
+ b = add(10, 10, out=out)
+ assert b==out
+ assert b.dtype == out.dtype
+
+ def test_applevel(self):
+ from _numpypy import array, sum, max, min
+ a = array([[1, 2], [3, 4]])
+ out = array([[0, 0], [0, 0]])
+ c = sum(a, axis=0, out=out[0])
+ assert (c == [4, 6]).all()
+ assert (c == out[0]).all()
+ assert (c != out[1]).all()
+ c = max(a, axis=1, out=out[0])
+ assert (c == [2, 4]).all()
+ assert (c == out[0]).all()
+ assert (c != out[1]).all()
+
+ def test_ufunc_cast(self):
+ from _numpypy import array, negative, add, sum
+ a = array(16, dtype = int)
+ c = array(0, dtype = float)
+ b = negative(a, out=c)
+ assert b == c
+ b = add(a, a, out=c)
+ assert b == c
+ d = array([16, 16], dtype=int)
+ b = sum(d, out=c)
+ assert b == c
+ try:
+ from _numpypy import version
+ v = version.version.split('.')
+ except:
+ v = ['1', '6', '0'] # numpypy is api compatable to what version?
+ if v[0]<'2':
+ b = negative(c, out=a)
+ assert b == a
+ b = add(c, c, out=a)
+ assert b == a
+ b = sum(array([16, 16], dtype=float), out=a)
+ assert b == a
+ else:
+ cast_error = raises(TypeError, negative, c, a)
+ assert str(cast_error.value) == \
+ "Cannot cast ufunc negative output from dtype('float64') to dtype('int64') with casting rule 'same_kind'"
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
@@ -131,7 +131,7 @@
# bogus. We need to improve the situation somehow.
self.check_simple_loop({'getinteriorfield_raw': 2,
'setinteriorfield_raw': 1,
- 'arraylen_gc': 1,
+ 'arraylen_gc': 2,
'guard_true': 1,
'int_lt': 1,
'jump': 1,
diff --git a/pypy/module/pypyjit/test_pypy_c/test_containers.py b/pypy/module/pypyjit/test_pypy_c/test_containers.py
--- a/pypy/module/pypyjit/test_pypy_c/test_containers.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_containers.py
@@ -128,3 +128,82 @@
loop, = log.loops_by_filename(self.filepath)
ops = loop.ops_by_id('look')
assert 'call' not in log.opnames(ops)
+
+ #XXX the following tests only work with strategies enabled
+
+ def test_should_not_create_intobject_with_sets(self):
+ def main(n):
+ i = 0
+ s = set()
+ while i < n:
+ s.add(i)
+ i += 1
+ log = self.run(main, [1000])
+ assert log.result == main(1000)
+ loop, = log.loops_by_filename(self.filepath)
+ opnames = log.opnames(loop.allops())
+ assert opnames.count('new_with_vtable') == 0
+
+ def test_should_not_create_stringobject_with_sets(self):
+ def main(n):
+ i = 0
+ s = set()
+ while i < n:
+ s.add(str(i))
+ i += 1
+ log = self.run(main, [1000])
+ assert log.result == main(1000)
+ loop, = log.loops_by_filename(self.filepath)
+ opnames = log.opnames(loop.allops())
+ assert opnames.count('new_with_vtable') == 0
+
+ def test_should_not_create_intobject_with_lists(self):
+ def main(n):
+ i = 0
+ l = []
+ while i < n:
+ l.append(i)
+ i += 1
+ log = self.run(main, [1000])
+ assert log.result == main(1000)
+ loop, = log.loops_by_filename(self.filepath)
+ opnames = log.opnames(loop.allops())
+ assert opnames.count('new_with_vtable') == 0
+
+ def test_should_not_create_stringobject_with_lists(self):
+ def main(n):
+ i = 0
+ l = []
+ while i < n:
+ l.append(str(i))
+ i += 1
+ log = self.run(main, [1000])
+ assert log.result == main(1000)
+ loop, = log.loops_by_filename(self.filepath)
+ opnames = log.opnames(loop.allops())
+ assert opnames.count('new_with_vtable') == 0
+
+ def test_optimized_create_list_from_string(self):
+ def main(n):
+ i = 0
+ l = []
+ while i < n:
+ l = list("abc" * i)
+ i += 1
+ log = self.run(main, [1000])
+ assert log.result == main(1000)
+ loop, = log.loops_by_filename(self.filepath)
+ opnames = log.opnames(loop.allops())
+ assert opnames.count('new_with_vtable') == 0
+
+ def test_optimized_create_set_from_list(self):
+ def main(n):
+ i = 0
+ while i < n:
+ s = set([1,2,3])
+ i += 1
+ log = self.run(main, [1000])
+ assert log.result == main(1000)
+ loop, = log.loops_by_filename(self.filepath)
+ opnames = log.opnames(loop.allops())
+ assert opnames.count('new_with_vtable') == 0
diff --git a/pypy/objspace/flow/test/test_objspace.py b/pypy/objspace/flow/test/test_objspace.py
--- a/pypy/objspace/flow/test/test_objspace.py
+++ b/pypy/objspace/flow/test/test_objspace.py
@@ -1,6 +1,6 @@
from __future__ import with_statement
import new
-import py
+import py, sys
from pypy.objspace.flow.model import Constant, Block, Link, Variable
from pypy.objspace.flow.model import mkentrymap, c_last_exception
from pypy.interpreter.argument import Arguments
@@ -893,6 +893,8 @@
""" Tests code generated by pypy-c compiled with BUILD_LIST_FROM_ARG
bytecode
"""
+ if sys.version_info < (2, 7):
+ py.test.skip("2.7 only test")
self.patch_opcodes('BUILD_LIST_FROM_ARG')
try:
def f():
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
@@ -111,9 +111,15 @@
length = len(data)
start, stop, step, slicelength = w_slice.indices4(space, length)
assert slicelength >= 0
- newdata = [data[start + i*step] for i in range(slicelength)]
+ if step == 1 and 0 <= start <= stop:
+ newdata = data[start:stop]
+ else:
+ newdata = _getitem_slice_multistep(data, start, step, slicelength)
return W_BytearrayObject(newdata)
+def _getitem_slice_multistep(data, start, step, slicelength):
+ return [data[start + i*step] for i in range(slicelength)]
+
def contains__Bytearray_Int(space, w_bytearray, w_char):
char = space.int_w(w_char)
if not 0 <= char < 256:
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
@@ -127,10 +127,10 @@
def iter(self, w_dict):
return ModuleDictIteratorImplementation(self.space, self, w_dict)
- def keys(self, w_dict):
+ def w_keys(self, w_dict):
space = self.space
- iterator = self.unerase(w_dict.dstorage).iteritems
- return [space.wrap(key) for key, cell in iterator()]
+ l = self.unerase(w_dict.dstorage).keys()
+ return space.newlist_str(l)
def values(self, w_dict):
iterator = self.unerase(w_dict.dstorage).itervalues
diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py
--- a/pypy/objspace/std/dictmultiobject.py
+++ b/pypy/objspace/std/dictmultiobject.py
@@ -90,9 +90,9 @@
def _add_indirections():
dict_methods = "setitem setitem_str getitem \
getitem_str delitem length \
- clear keys values \
+ clear w_keys values \
items iter setdefault \
- popitem".split()
+ popitem listview_str listview_int".split()
def make_method(method):
def f(self, *args):
@@ -113,7 +113,7 @@
def get_empty_storage(self):
raise NotImplementedError
- def keys(self, w_dict):
+ def w_keys(self, w_dict):
iterator = self.iter(w_dict)
result = []
while 1:
@@ -121,7 +121,7 @@
if w_key is not None:
result.append(w_key)
else:
- return result
+ return self.space.newlist(result)
def values(self, w_dict):
iterator = self.iter(w_dict)
@@ -160,6 +160,11 @@
w_dict.strategy = strategy
w_dict.dstorage = storage
+ def listview_str(self, w_dict):
+ return None
+
+ def listview_int(self, w_dict):
+ return None
class EmptyDictStrategy(DictStrategy):
@@ -371,8 +376,9 @@
self.switch_to_object_strategy(w_dict)
return w_dict.getitem(w_key)
- def keys(self, w_dict):
- return [self.wrap(key) for key in self.unerase(w_dict.dstorage).iterkeys()]
+ def w_keys(self, w_dict):
+ l = [self.wrap(key) for key in self.unerase(w_dict.dstorage).iterkeys()]
+ return self.space.newlist(l)
def values(self, w_dict):
return self.unerase(w_dict.dstorage).values()
@@ -425,8 +431,8 @@
def iter(self, w_dict):
return ObjectIteratorImplementation(self.space, self, w_dict)
- def keys(self, w_dict):
- return self.unerase(w_dict.dstorage).keys()
+ def w_keys(self, w_dict):
+ return self.space.newlist(self.unerase(w_dict.dstorage).keys())
class StringDictStrategy(AbstractTypedStrategy, DictStrategy):
@@ -469,9 +475,15 @@
assert key is not None
return self.unerase(w_dict.dstorage).get(key, None)
+ def listview_str(self, w_dict):
+ return self.unerase(w_dict.dstorage).keys()
+
def iter(self, w_dict):
return StrIteratorImplementation(self.space, self, w_dict)
+ def w_keys(self, w_dict):
+ return self.space.newlist_str(self.listview_str(w_dict))
+
class _WrappedIteratorMixin(object):
_mixin_ = True
@@ -534,6 +546,14 @@
def iter(self, w_dict):
return IntIteratorImplementation(self.space, self, w_dict)
+ def listview_int(self, w_dict):
+ return self.unerase(w_dict.dstorage).keys()
+
+ def w_keys(self, w_dict):
+ # XXX there is no space.newlist_int yet
+ space = self.space
+ return space.call_function(space.w_list, w_dict)
+
class IntIteratorImplementation(_WrappedIteratorMixin, IteratorImplementation):
pass
@@ -688,7 +708,7 @@
return space.newlist(w_self.items())
def dict_keys__DictMulti(space, w_self):
- return space.newlist(w_self.keys())
+ return w_self.w_keys()
def dict_values__DictMulti(space, w_self):
return space.newlist(w_self.values())
diff --git a/pypy/objspace/std/dictproxyobject.py b/pypy/objspace/std/dictproxyobject.py
--- a/pypy/objspace/std/dictproxyobject.py
+++ b/pypy/objspace/std/dictproxyobject.py
@@ -76,7 +76,7 @@
def keys(self, w_dict):
space = self.space
- return [space.wrap(key) for key in self.unerase(w_dict.dstorage).dict_w.iterkeys()]
+ return space.newlist_str(self.unerase(w_dict.dstorage).dict_w.keys())
def values(self, w_dict):
return [unwrap_cell(self.space, w_value) for w_value in self.unerase(w_dict.dstorage).dict_w.itervalues()]
diff --git a/pypy/objspace/std/dicttype.py b/pypy/objspace/std/dicttype.py
--- a/pypy/objspace/std/dicttype.py
+++ b/pypy/objspace/std/dicttype.py
@@ -62,8 +62,14 @@
w_fill = space.w_None
if space.is_w(w_type, space.w_dict):
w_dict = W_DictMultiObject.allocate_and_init_instance(space, w_type)
- for w_key in space.listview(w_keys):
- w_dict.setitem(w_key, w_fill)
+
+ strlist = space.listview_str(w_keys)
+ if strlist is not None:
+ for key in strlist:
+ w_dict.setitem_str(key, w_fill)
+ else:
+ for w_key in space.listview(w_keys):
+ w_dict.setitem(w_key, w_fill)
else:
w_dict = space.call_function(w_type)
for w_key in space.listview(w_keys):
diff --git a/pypy/objspace/std/frozensettype.py b/pypy/objspace/std/frozensettype.py
--- a/pypy/objspace/std/frozensettype.py
+++ b/pypy/objspace/std/frozensettype.py
@@ -39,13 +39,11 @@
def descr__frozenset__new__(space, w_frozensettype,
w_iterable=gateway.NoneNotWrapped):
from pypy.objspace.std.setobject import W_FrozensetObject
- from pypy.objspace.std.setobject import make_setdata_from_w_iterable
if (space.is_w(w_frozensettype, space.w_frozenset) and
w_iterable is not None and type(w_iterable) is W_FrozensetObject):
return w_iterable
w_obj = space.allocate_instance(W_FrozensetObject, w_frozensettype)
- data = make_setdata_from_w_iterable(space, w_iterable)
- W_FrozensetObject.__init__(w_obj, space, data)
+ W_FrozensetObject.__init__(w_obj, space, w_iterable)
return w_obj
frozenset_typedef = StdTypeDef("frozenset",
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
@@ -29,9 +29,8 @@
class W_SeqIterObject(W_AbstractSeqIterObject):
"""Sequence iterator implementation for general sequences."""
-class W_FastListIterObject(W_AbstractSeqIterObject):
- """Sequence iterator specialized for lists, accessing directly their
- RPython-level list of wrapped objects.
+class W_FastListIterObject(W_AbstractSeqIterObject): # XXX still needed
+ """Sequence iterator specialized for lists.
"""
class W_FastTupleIterObject(W_AbstractSeqIterObject):
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
@@ -139,6 +139,16 @@
new erased object as storage"""
self.strategy.init_from_list_w(self, list_w)
+ def clear(self, space):
+ """Initializes (or overrides) the listobject as empty."""
+ self.space = space
+ if space.config.objspace.std.withliststrategies:
+ strategy = space.fromcache(EmptyListStrategy)
+ else:
+ strategy = space.fromcache(ObjectListStrategy)
+ self.strategy = strategy
+ strategy.clear(self)
+
def clone(self):
"""Returns a clone by creating a new listobject
with the same strategy and a copy of the storage"""
@@ -200,6 +210,11 @@
""" 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 getitems_int(self):
+ """ Return the items in the list as unwrapped ints. If the list does
+ not use the list strategy, return None. """
+ return self.strategy.getitems_int(self)
# ___________________________________________________
@@ -300,6 +315,9 @@
def getitems_str(self, w_list):
return None
+ def getitems_int(self, w_list):
+ return None
+
def getstorage_copy(self, w_list):
raise NotImplementedError
@@ -358,6 +376,9 @@
assert len(list_w) == 0
w_list.lstorage = self.erase(None)
+ def clear(self, w_list):
+ w_list.lstorage = self.erase(None)
+
erase, unerase = rerased.new_erasing_pair("empty")
erase = staticmethod(erase)
unerase = staticmethod(unerase)
@@ -516,6 +537,9 @@
raise IndexError
return start + i * step
+ def getitems_int(self, w_list):
+ return self._getitems_range(w_list, False)
+
def getitem(self, w_list, i):
return self.wrap(self._getitem_unwrapped(w_list, i))
@@ -696,6 +720,7 @@
for i in l:
if i == obj:
return True
+ return False
return ListStrategy.contains(self, w_list, w_obj)
def length(self, w_list):
@@ -937,6 +962,9 @@
def init_from_list_w(self, w_list, list_w):
w_list.lstorage = self.erase(list_w)
+ def clear(self, w_list):
+ w_list.lstorage = self.erase([])
+
def contains(self, w_list, w_obj):
return ListStrategy.contains(self, w_list, w_obj)
@@ -970,6 +998,9 @@
if reverse:
l.reverse()
+ def getitems_int(self, w_list):
+ return self.unerase(w_list.lstorage)
+
class FloatListStrategy(AbstractUnwrappedStrategy, ListStrategy):
_none_value = 0.0
_applevel_repr = "float"
@@ -1027,37 +1058,49 @@
def getitems_str(self, w_list):
return self.unerase(w_list.lstorage)
-
# _______________________________________________________
init_signature = Signature(['sequence'], None, None)
init_defaults = [None]
def init__List(space, w_list, __args__):
- from pypy.objspace.std.tupleobject import W_TupleObject
+ from pypy.objspace.std.tupleobject import W_AbstractTupleObject
# this is on the silly side
w_iterable, = __args__.parse_obj(
None, 'list', init_signature, init_defaults)
- w_list.__init__(space, [])
+ w_list.clear(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):
- w_list.extend(w_iterable)
- elif isinstance(w_iterable, W_TupleObject):
- w_list.extend(W_ListObject(space, w_iterable.wrappeditems[:]))
- else:
- _init_from_iterable(space, w_list, w_iterable)
+ if type(w_iterable) is W_ListObject:
+ w_iterable.copy_into(w_list)
+ return
+ elif isinstance(w_iterable, W_AbstractTupleObject):
+ w_list.__init__(space, w_iterable.getitems_copy())
+ return
+
+ intlist = space.listview_int(w_iterable)
+ if intlist is not None:
+ w_list.strategy = strategy = space.fromcache(IntegerListStrategy)
+ # need to copy because intlist can share with w_iterable
+ w_list.lstorage = strategy.erase(intlist[:])
+ return
+
+ strlist = space.listview_str(w_iterable)
+ if strlist is not None:
+ w_list.strategy = strategy = space.fromcache(StringListStrategy)
+ # need to copy because intlist can share with w_iterable
+ w_list.lstorage = strategy.erase(strlist[:])
+ return
+
+ # xxx special hack for speed
+ from pypy.interpreter.generator import GeneratorIterator
+ if isinstance(w_iterable, GeneratorIterator):
+ w_iterable.unpack_into_w(w_list)
+ return
+ # /xxx
+ _init_from_iterable(space, w_list, 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_w(w_list)
- return
- # /xxx
w_iterator = space.iter(w_iterable)
while True:
try:
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
@@ -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, space, [])
+ w_obj.clear(space)
return w_obj
# ____________________________________________________________
diff --git a/pypy/objspace/std/mapdict.py b/pypy/objspace/std/mapdict.py
--- a/pypy/objspace/std/mapdict.py
+++ b/pypy/objspace/std/mapdict.py
@@ -694,6 +694,8 @@
self.delitem(w_dict, w_key)
return (w_key, w_value)
+ # XXX could implement a more efficient w_keys based on space.newlist_str
+
def materialize_r_dict(space, obj, dict_w):
map = obj._get_mapdict_map()
new_obj = map.materialize_r_dict(space, obj, dict_w)
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
@@ -227,10 +227,7 @@
return W_ComplexObject(x.real, x.imag)
if isinstance(x, set):
- rdict_w = r_dict(self.eq_w, self.hash_w)
- for item in x:
- rdict_w[self.wrap(item)] = None
- res = W_SetObject(self, rdict_w)
+ res = W_SetObject(self, self.newlist([self.wrap(item) for item in x]))
return res
if isinstance(x, frozenset):
@@ -325,7 +322,7 @@
def newset(self):
from pypy.objspace.std.setobject import newset
- return W_SetObject(self, newset(self))
+ return W_SetObject(self, None)
def newslice(self, w_start, w_end, w_step):
return W_SliceObject(w_start, w_end, w_step)
@@ -403,7 +400,7 @@
def unpackiterable(self, w_obj, expected_length=-1):
if isinstance(w_obj, W_AbstractTupleObject):
t = w_obj.getitems_copy()
- elif isinstance(w_obj, W_ListObject):
+ elif type(w_obj) is W_ListObject:
t = w_obj.getitems_copy()
else:
return ObjSpace.unpackiterable(self, w_obj, expected_length)
@@ -417,7 +414,7 @@
"""
if isinstance(w_obj, W_AbstractTupleObject):
t = w_obj.tolist()
- elif isinstance(w_obj, W_ListObject):
+ elif type(w_obj) is W_ListObject:
if unroll:
t = w_obj.getitems_unroll()
else:
@@ -438,7 +435,7 @@
return self.fixedview(w_obj, expected_length, unroll=True)
def listview(self, w_obj, expected_length=-1):
- if isinstance(w_obj, W_ListObject):
+ if type(w_obj) is W_ListObject:
t = w_obj.getitems()
elif isinstance(w_obj, W_AbstractTupleObject):
t = w_obj.getitems_copy()
@@ -449,8 +446,25 @@
return t
def listview_str(self, w_obj):
- if isinstance(w_obj, W_ListObject):
+ # note: uses exact type checking for objects with strategies,
+ # and isinstance() for others. See test_listobject.test_uses_custom...
+ if type(w_obj) is W_ListObject:
return w_obj.getitems_str()
+ if type(w_obj) is W_DictMultiObject:
+ return w_obj.listview_str()
+ if type(w_obj) is W_SetObject or type(w_obj) is W_FrozensetObject:
+ return w_obj.listview_str()
+ if isinstance(w_obj, W_StringObject):
+ return w_obj.listview_str()
+ return None
+
+ def listview_int(self, w_obj):
+ if type(w_obj) is W_ListObject:
+ return w_obj.getitems_int()
+ if type(w_obj) is W_DictMultiObject:
+ return w_obj.listview_int()
+ if type(w_obj) is W_SetObject or type(w_obj) is W_FrozensetObject:
+ return w_obj.listview_int()
return None
def sliceindices(self, w_slice, w_length):
diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py
--- a/pypy/objspace/std/setobject.py
+++ b/pypy/objspace/std/setobject.py
@@ -7,6 +7,12 @@
from pypy.interpreter.argument import Signature
from pypy.objspace.std.settype import set_typedef as settypedef
from pypy.objspace.std.frozensettype import frozenset_typedef as frozensettypedef
+from pypy.rlib import rerased
+from pypy.rlib.objectmodel import instantiate
+from pypy.interpreter.generator import GeneratorIterator
+from pypy.objspace.std.listobject import W_ListObject
+from pypy.objspace.std.intobject import W_IntObject
+from pypy.objspace.std.stringobject import W_StringObject
class W_BaseSetObject(W_Object):
typedef = None
@@ -20,88 +26,859 @@
return True
return False
-
- def __init__(w_self, space, setdata):
+ def __init__(w_self, space, w_iterable=None):
"""Initialize the set by taking ownership of 'setdata'."""
- assert setdata is not None
- w_self.setdata = setdata
+ w_self.space = space
+ set_strategy_and_setdata(space, w_self, w_iterable)
def __repr__(w_self):
"""representation for debugging purposes"""
- reprlist = [repr(w_item) for w_item in w_self.setdata.keys()]
+ reprlist = [repr(w_item) for w_item in w_self.getkeys()]
return "<%s(%s)>" % (w_self.__class__.__name__, ', '.join(reprlist))
+ def from_storage_and_strategy(w_self, storage, strategy):
+ obj = w_self._newobj(w_self.space, None)
+ assert isinstance(obj, W_BaseSetObject)
+ obj.strategy = strategy
+ obj.sstorage = storage
+ return obj
+
_lifeline_ = None
def getweakref(self):
return self._lifeline_
+
def setweakref(self, space, weakreflifeline):
self._lifeline_ = weakreflifeline
def delweakref(self):
self._lifeline_ = None
+ def switch_to_object_strategy(self, space):
+ d = self.strategy.getdict_w(self)
+ self.strategy = strategy = space.fromcache(ObjectSetStrategy)
+ self.sstorage = strategy.erase(d)
+
+ def switch_to_empty_strategy(self):
+ self.strategy = strategy = self.space.fromcache(EmptySetStrategy)
+ self.sstorage = strategy.get_empty_storage()
+
+ # _____________ strategy methods ________________
+
+
+ def clear(self):
+ """ Removes all elements from the set. """
+ self.strategy.clear(self)
+
+ def copy_real(self):
+ """ Returns a clone of the set. Frozensets storages are also copied."""
+ return self.strategy.copy_real(self)
+
+ def length(self):
+ """ Returns the number of items inside the set. """
+ return self.strategy.length(self)
+
+ def add(self, w_key):
+ """ Adds an element to the set. The element must be wrapped. """
+ self.strategy.add(self, w_key)
+
+ def remove(self, w_item):
+ """ Removes the given element from the set. Element must be wrapped. """
+ return self.strategy.remove(self, w_item)
+
+ def getdict_w(self):
+ """ Returns a dict with all elements of the set. Needed only for switching to ObjectSetStrategy. """
+ return self.strategy.getdict_w(self)
+
+ def listview_str(self):
+ """ If this is a string set return its contents as a list of uwnrapped strings. Otherwise return None. """
+ return self.strategy.listview_str(self)
+
+ def listview_int(self):
+ """ If this is an int set return its contents as a list of uwnrapped ints. Otherwise return None. """
+ return self.strategy.listview_int(self)
+
+ def get_storage_copy(self):
+ """ Returns a copy of the storage. Needed when we want to clone all elements from one set and
+ put them into another. """
+ return self.strategy.get_storage_copy(self)
+
+ def getkeys(self):
+ """ Returns a list of all elements inside the set. Only used in __repr__. Use as less as possible."""
+ return self.strategy.getkeys(self)
+
+ def difference(self, w_other):
+ """ Returns a set with all items that are in this set, but not in w_other. W_other must be a set."""
+ return self.strategy.difference(self, w_other)
+
+ def difference_update(self, w_other):
+ """ As difference but overwrites the sets content with the result. W_other must be a set."""
+ self.strategy.difference_update(self, w_other)
+
+ def symmetric_difference(self, w_other):
+ """ Returns a set with all items that are either in this set or in w_other, but not in both. W_other must be a set. """
+ return self.strategy.symmetric_difference(self, w_other)
+
+ def symmetric_difference_update(self, w_other):
+ """ As symmetric_difference but overwrites the content of the set with the result. W_other must be a set."""
+ self.strategy.symmetric_difference_update(self, w_other)
+
+ def intersect(self, w_other):
+ """ Returns a set with all items that exists in both sets, this set and in w_other. W_other must be a set. """
+ return self.strategy.intersect(self, w_other)
+
+ def intersect_update(self, w_other):
+ """ Keeps only those elements found in both sets, removing all other elements. W_other must be a set."""
+ self.strategy.intersect_update(self, w_other)
+
+ def issubset(self, w_other):
+ """ Checks wether this set is a subset of w_other. W_other must be a set. """
+ return self.strategy.issubset(self, w_other)
+
+ def isdisjoint(self, w_other):
+ """ Checks wether this set and the w_other are completly different, i.e. have no equal elements. W_other must be a set."""
+ return self.strategy.isdisjoint(self, w_other)
+
+ def update(self, w_other):
+ """ Appends all elements from the given set to this set. W_other must be a set."""
+ self.strategy.update(self, w_other)
+
+ def has_key(self, w_key):
+ """ Checks wether this set contains the given wrapped key."""
+ return self.strategy.has_key(self, w_key)
+
+ def equals(self, w_other):
+ """ Checks wether this set and the given set are equal, i.e. contain the same elements. W_other must be a set."""
+ return self.strategy.equals(self, w_other)
+
+ def iter(self):
+ """ Returns an iterator of the elements from this set. """
+ return self.strategy.iter(self)
+
+ def popitem(self):
+ """ Removes an arbitrary element from the set. May raise KeyError if set is empty."""
+ return self.strategy.popitem(self)
+
class W_SetObject(W_BaseSetObject):
from pypy.objspace.std.settype import set_typedef as typedef
- def _newobj(w_self, space, rdict_w):
- """Make a new set by taking ownership of 'rdict_w'."""
+ def _newobj(w_self, space, w_iterable):
+ """Make a new set by taking ownership of 'w_iterable'."""
if type(w_self) is W_SetObject:
- return W_SetObject(space, rdict_w)
+ return W_SetObject(space, w_iterable)
w_type = space.type(w_self)
w_obj = space.allocate_instance(W_SetObject, w_type)
- W_SetObject.__init__(w_obj, space, rdict_w)
+ W_SetObject.__init__(w_obj, space, w_iterable)
return w_obj
class W_FrozensetObject(W_BaseSetObject):
from pypy.objspace.std.frozensettype import frozenset_typedef as typedef
hash = 0
- def _newobj(w_self, space, rdict_w):
- """Make a new frozenset by taking ownership of 'rdict_w'."""
+ def _newobj(w_self, space, w_iterable):
+ """Make a new frozenset by taking ownership of 'w_iterable'."""
if type(w_self) is W_FrozensetObject:
- return W_FrozensetObject(space, rdict_w)
+ return W_FrozensetObject(space, w_iterable)
w_type = space.type(w_self)
w_obj = space.allocate_instance(W_FrozensetObject, w_type)
- W_FrozensetObject.__init__(w_obj, space, rdict_w)
+ W_FrozensetObject.__init__(w_obj, space, w_iterable)
return w_obj
registerimplementation(W_BaseSetObject)
registerimplementation(W_SetObject)
registerimplementation(W_FrozensetObject)
-class W_SetIterObject(W_Object):
- from pypy.objspace.std.settype import setiter_typedef as typedef
+class SetStrategy(object):
+ def __init__(self, space):
+ self.space = space
- def __init__(w_self, setdata):
- w_self.content = content = setdata
- w_self.len = len(content)
- w_self.pos = 0
- w_self.iterator = w_self.content.iterkeys()
+ def get_empty_dict(self):
+ """ Returns an empty dictionary depending on the strategy. Used to initalize a new storage. """
+ raise NotImplementedError
- def next_entry(w_self):
- for w_key in w_self.iterator:
+ def get_empty_storage(self):
+ """ Returns an empty storage (erased) object. Used to initialize an empty set."""
+ raise NotImplementedError
+
+ def listview_str(self, w_set):
+ return None
+
+ def listview_int(self, w_set):
+ return None
+
+ #def erase(self, storage):
+ # raise NotImplementedError
+
+ #def unerase(self, storage):
+ # raise NotImplementedError
+
+ # __________________ methods called on W_SetObject _________________
+
+ def clear(self, w_set):
+ raise NotImplementedError
+
+ def copy_real(self, w_set):
+ raise NotImplementedError
+
+ def length(self, w_set):
+ raise NotImplementedError
+
+ def add(self, w_set, w_key):
+ raise NotImplementedError
+
+ def remove(self, w_set, w_item):
+ raise NotImplementedError
+
+ def getdict_w(self, w_set):
+ raise NotImplementedError
+
+ def get_storage_copy(self, w_set):
+ raise NotImplementedError
+
+ def getkeys(self, w_set):
+ raise NotImplementedError
+
+ def difference(self, w_set, w_other):
+ raise NotImplementedError
+
+ def difference_update(self, w_set, w_other):
+ raise NotImplementedError
+
+ def symmetric_difference(self, w_set, w_other):
+ raise NotImplementedError
+
+ def symmetric_difference_update(self, w_set, w_other):
+ raise NotImplementedError
+
+ def intersect(self, w_set, w_other):
+ raise NotImplementedError
+
+ def intersect_update(self, w_set, w_other):
+ raise NotImplementedError
+
+ def issubset(self, w_set, w_other):
+ raise NotImplementedError
+
+ def isdisjoint(self, w_set, w_other):
+ raise NotImplementedError
+
+ def update(self, w_set, w_other):
+ raise NotImplementedError
+
+ def has_key(self, w_set, w_key):
+ raise NotImplementedError
+
+ def equals(self, w_set, w_other):
+ raise NotImplementedError
+
+ def iter(self, w_set):
+ raise NotImplementedError
+
+ def popitem(self, w_set):
+ raise NotImplementedError
+
+class EmptySetStrategy(SetStrategy):
+
+ erase, unerase = rerased.new_erasing_pair("empty")
+ erase = staticmethod(erase)
+ unerase = staticmethod(unerase)
+
+ def get_empty_storage(self):
+ return self.erase(None)
+
+ def is_correct_type(self, w_key):
+ return False
+
+ def length(self, w_set):
+ return 0
+
+ def clear(self, w_set):
+ pass
+
+ def copy_real(self, w_set):
+ storage = self.erase(None)
+ clone = w_set.from_storage_and_strategy(storage, self)
+ return clone
+
+ def add(self, w_set, w_key):
+ if type(w_key) is W_IntObject:
+ strategy = self.space.fromcache(IntegerSetStrategy)
+ elif type(w_key) is W_StringObject:
+ strategy = self.space.fromcache(StringSetStrategy)
+ else:
+ strategy = self.space.fromcache(ObjectSetStrategy)
+ w_set.strategy = strategy
+ w_set.sstorage = strategy.get_empty_storage()
+ w_set.add(w_key)
+
+ def remove(self, w_set, w_item):
+ return False
+
+ def getdict_w(self, w_set):
+ return newset(self.space)
+
+ def get_storage_copy(self, w_set):
+ return w_set.sstorage
+
+ def getkeys(self, w_set):
+ return []
+
+ def has_key(self, w_set, w_key):
+ return False
+
+ def equals(self, w_set, w_other):
+ if w_other.strategy is self or w_other.length() == 0:
+ return True
+ return False
+
+ def difference(self, w_set, w_other):
+ return w_set.copy_real()
+
+ def difference_update(self, w_set, w_other):
+ pass
+
+ def intersect(self, w_set, w_other):
+ return w_set.copy_real()
+
+ def intersect_update(self, w_set, w_other):
+ pass
+
+ def isdisjoint(self, w_set, w_other):
+ return True
+
+ def issubset(self, w_set, w_other):
+ return True
+
+ def symmetric_difference(self, w_set, w_other):
+ return w_other.copy_real()
+
+ def symmetric_difference_update(self, w_set, w_other):
+ w_set.strategy = w_other.strategy
+ w_set.sstorage = w_other.get_storage_copy()
+
+ def update(self, w_set, w_other):
+ w_set.strategy = w_other.strategy
+ w_set.sstorage = w_other.get_storage_copy()
+
+ def iter(self, w_set):
+ return EmptyIteratorImplementation(self.space, w_set)
+
+ def popitem(self, w_set):
+ raise OperationError(self.space.w_KeyError,
+ self.space.wrap('pop from an empty set'))
+
+class AbstractUnwrappedSetStrategy(object):
+ _mixin_ = True
+
+ def is_correct_type(self, w_key):
+ """ Checks wether the given wrapped key fits this strategy."""
+ raise NotImplementedError
+
+ def unwrap(self, w_item):
+ """ Returns the unwrapped value of the given wrapped item."""
+ raise NotImplementedError
+
+ def wrap(self, item):
+ """ Returns a wrapped version of the given unwrapped item. """
+ raise NotImplementedError
+
+ def get_storage_from_list(self, list_w):
+ setdata = self.get_empty_dict()
+ for w_item in list_w:
+ setdata[self.unwrap(w_item)] = None
+ return self.erase(setdata)
+
+ def get_storage_from_unwrapped_list(self, items):
+ setdata = self.get_empty_dict()
+ for item in items:
+ setdata[item] = None
+ return self.erase(setdata)
+
+ def length(self, w_set):
+ return len(self.unerase(w_set.sstorage))
+
+ def clear(self, w_set):
+ w_set.switch_to_empty_strategy()
+
+ def copy_real(self, w_set):
+ # may be used internally on frozen sets, although frozenset().copy()
+ # returns self in frozenset_copy__Frozenset.
+ strategy = w_set.strategy
+ d = self.unerase(w_set.sstorage)
+ storage = self.erase(d.copy())
+ clone = w_set.from_storage_and_strategy(storage, strategy)
+ return clone
+
+ def add(self, w_set, w_key):
+ if self.is_correct_type(w_key):
+ d = self.unerase(w_set.sstorage)
+ d[self.unwrap(w_key)] = None
+ else:
+ w_set.switch_to_object_strategy(self.space)
+ w_set.add(w_key)
+
+ def remove(self, w_set, w_item):
+ from pypy.objspace.std.dictmultiobject import _never_equal_to_string
+ d = self.unerase(w_set.sstorage)
+ if not self.is_correct_type(w_item):
+ #XXX check type of w_item and immediately return False in some cases
+ w_set.switch_to_object_strategy(self.space)
+ return w_set.remove(w_item)
+
+ key = self.unwrap(w_item)
+ try:
+ del d[key]
+ return True
+ except KeyError:
+ return False
+
+ def getdict_w(self, w_set):
+ result = newset(self.space)
+ keys = self.unerase(w_set.sstorage).keys()
+ for key in keys:
+ result[self.wrap(key)] = None
+ return result
+
+ def get_storage_copy(self, w_set):
+ d = self.unerase(w_set.sstorage)
+ copy = self.erase(d.copy())
+ return copy
+
+ def getkeys(self, w_set):
+ keys = self.unerase(w_set.sstorage).keys()
+ keys_w = [self.wrap(key) for key in keys]
+ return keys_w
+
+ def has_key(self, w_set, w_key):
+ from pypy.objspace.std.dictmultiobject import _never_equal_to_string
+ if not self.is_correct_type(w_key):
+ #XXX check type of w_item and immediately return False in some cases
+ w_set.switch_to_object_strategy(self.space)
+ return w_set.has_key(w_key)
+ d = self.unerase(w_set.sstorage)
+ return self.unwrap(w_key) in d
+
+ def equals(self, w_set, w_other):
+ if w_set.length() != w_other.length():
+ return False
+ items = self.unerase(w_set.sstorage).keys()
+ for key in items:
+ if not w_other.has_key(self.wrap(key)):
+ return False
+ return True
+
+ def _difference_wrapped(self, w_set, w_other):
+ strategy = self.space.fromcache(ObjectSetStrategy)
+
+ d_new = strategy.get_empty_dict()
+ for obj in self.unerase(w_set.sstorage):
+ w_item = self.wrap(obj)
+ if not w_other.has_key(w_item):
+ d_new[w_item] = None
+
+ return strategy.erase(d_new)
+
+ def _difference_unwrapped(self, w_set, w_other):
+ iterator = self.unerase(w_set.sstorage).iterkeys()
+ other_dict = self.unerase(w_other.sstorage)
+ result_dict = self.get_empty_dict()
+ for key in iterator:
+ if key not in other_dict:
+ result_dict[key] = None
+ return self.erase(result_dict)
+
+ def _difference_base(self, w_set, w_other):
+ if self is w_other.strategy:
+ strategy = w_set.strategy
+ storage = self._difference_unwrapped(w_set, w_other)
+ elif not w_set.strategy.may_contain_equal_elements(w_other.strategy):
+ strategy = w_set.strategy
+ storage = w_set.sstorage
+ else:
+ strategy = self.space.fromcache(ObjectSetStrategy)
+ storage = self._difference_wrapped(w_set, w_other)
+ return storage, strategy
+
+ def difference(self, w_set, w_other):
+ storage, strategy = self._difference_base(w_set, w_other)
+ w_newset = w_set.from_storage_and_strategy(storage, strategy)
+ return w_newset
+
+ def difference_update(self, w_set, w_other):
+ storage, strategy = self._difference_base(w_set, w_other)
+ w_set.strategy = strategy
+ w_set.sstorage = storage
+
+ def _symmetric_difference_unwrapped(self, w_set, w_other):
+ d_new = self.get_empty_dict()
+ d_this = self.unerase(w_set.sstorage)
+ d_other = self.unerase(w_other.sstorage)
+ for key in d_other.keys():
+ if not key in d_this:
+ d_new[key] = None
+ for key in d_this.keys():
+ if not key in d_other:
+ d_new[key] = None
+
+ storage = self.erase(d_new)
+ return storage
+
+ def _symmetric_difference_wrapped(self, w_set, w_other):
+ newsetdata = newset(self.space)
+ for obj in self.unerase(w_set.sstorage):
+ w_item = self.wrap(obj)
+ if not w_other.has_key(w_item):
+ newsetdata[w_item] = None
+
+ w_iterator = w_other.iter()
+ while True:
+ w_item = w_iterator.next_entry()
+ if w_item is None:
+ break
+ if not w_set.has_key(w_item):
+ newsetdata[w_item] = None
+
+ strategy = self.space.fromcache(ObjectSetStrategy)
+ return strategy.erase(newsetdata)
+
+ def _symmetric_difference_base(self, w_set, w_other):
+ if self is w_other.strategy:
+ strategy = w_set.strategy
+ storage = self._symmetric_difference_unwrapped(w_set, w_other)
+ else:
+ strategy = self.space.fromcache(ObjectSetStrategy)
+ storage = self._symmetric_difference_wrapped(w_set, w_other)
+ return storage, strategy
+
+ def symmetric_difference(self, w_set, w_other):
+ storage, strategy = self._symmetric_difference_base(w_set, w_other)
+ return w_set.from_storage_and_strategy(storage, strategy)
+
+ def symmetric_difference_update(self, w_set, w_other):
+ storage, strategy = self._symmetric_difference_base(w_set, w_other)
+ w_set.strategy = strategy
+ w_set.sstorage = storage
+
+ def _intersect_base(self, w_set, w_other):
+ if self is w_other.strategy:
+ strategy = w_set.strategy
+ storage = strategy._intersect_unwrapped(w_set, w_other)
+ elif not w_set.strategy.may_contain_equal_elements(w_other.strategy):
+ strategy = self.space.fromcache(EmptySetStrategy)
+ storage = strategy.get_empty_storage()
+ else:
+ strategy = self.space.fromcache(ObjectSetStrategy)
+ storage = self._intersect_wrapped(w_set, w_other)
+ return storage, strategy
+
+ def _intersect_wrapped(self, w_set, w_other):
+ result = newset(self.space)
+ for key in self.unerase(w_set.sstorage):
+ w_key = self.wrap(key)
+ if w_other.has_key(w_key):
+ result[w_key] = None
+
+ strategy = self.space.fromcache(ObjectSetStrategy)
+ return strategy.erase(result)
+
+ def _intersect_unwrapped(self, w_set, w_other):
+ result = self.get_empty_dict()
+ d_this = self.unerase(w_set.sstorage)
+ d_other = self.unerase(w_other.sstorage)
+ for key in d_this:
+ if key in d_other:
+ result[key] = None
+ return self.erase(result)
+
+ def intersect(self, w_set, w_other):
+ if w_set.length() > w_other.length():
+ return w_other.intersect(w_set)
+
+ storage, strategy = self._intersect_base(w_set, w_other)
+ return w_set.from_storage_and_strategy(storage, strategy)
+
+ def intersect_update(self, w_set, w_other):
+ if w_set.length() > w_other.length():
+ w_intersection = w_other.intersect(w_set)
+ strategy = w_intersection.strategy
+ storage = w_intersection.sstorage
+ else:
+ storage, strategy = self._intersect_base(w_set, w_other)
+ w_set.strategy = strategy
+ w_set.sstorage = storage
+
+ def _issubset_unwrapped(self, w_set, w_other):
+ d_other = self.unerase(w_other.sstorage)
+ for item in self.unerase(w_set.sstorage):
+ if not item in d_other:
+ return False
+ return True
+
+ def _issubset_wrapped(self, w_set, w_other):
+ for obj in self.unerase(w_set.sstorage):
+ w_item = self.wrap(obj)
+ if not w_other.has_key(w_item):
+ return False
+ return True
+
+ def issubset(self, w_set, w_other):
+ if w_set.length() == 0:
+ return True
+
+ if w_set.strategy is w_other.strategy:
+ return self._issubset_unwrapped(w_set, w_other)
+ elif not w_set.strategy.may_contain_equal_elements(w_other.strategy):
+ return False
+ else:
+ return self._issubset_wrapped(w_set, w_other)
+
+ def _isdisjoint_unwrapped(self, w_set, w_other):
+ d_set = self.unerase(w_set.sstorage)
+ d_other = self.unerase(w_other.sstorage)
+ for key in d_set:
+ if key in d_other:
+ return False
+ return True
+
+ def _isdisjoint_wrapped(self, w_set, w_other):
+ d = self.unerase(w_set.sstorage)
+ for key in d:
+ if w_other.has_key(self.wrap(key)):
+ return False
+ return True
+
+ def isdisjoint(self, w_set, w_other):
+ if w_other.length() == 0:
+ return True
+ if w_set.length() > w_other.length():
+ return w_other.isdisjoint(w_set)
+
+ if w_set.strategy is w_other.strategy:
+ return self._isdisjoint_unwrapped(w_set, w_other)
+ elif not w_set.strategy.may_contain_equal_elements(w_other.strategy):
+ return True
+ else:
+ return self._isdisjoint_wrapped(w_set, w_other)
+
+ def update(self, w_set, w_other):
+ if self is w_other.strategy:
+ d_set = self.unerase(w_set.sstorage)
+ d_other = self.unerase(w_other.sstorage)
+ d_set.update(d_other)
+ return
+
+ w_set.switch_to_object_strategy(self.space)
+ w_set.update(w_other)
+
+ def popitem(self, w_set):
+ storage = self.unerase(w_set.sstorage)
+ try:
+ # this returns a tuple because internally sets are dicts
+ result = storage.popitem()
+ except KeyError:
+ # strategy may still be the same even if dict is empty
+ raise OperationError(self.space.w_KeyError,
+ self.space.wrap('pop from an empty set'))
+ return self.wrap(result[0])
+
+class StringSetStrategy(AbstractUnwrappedSetStrategy, SetStrategy):
+ erase, unerase = rerased.new_erasing_pair("string")
+ erase = staticmethod(erase)
+ unerase = staticmethod(unerase)
+
+ def get_empty_storage(self):
+ return self.erase({})
+
+ def get_empty_dict(self):
+ return {}
+
+ def listview_str(self, w_set):
+ return self.unerase(w_set.sstorage).keys()
+
+ def is_correct_type(self, w_key):
+ return type(w_key) is W_StringObject
+
+ def may_contain_equal_elements(self, strategy):
+ if strategy is self.space.fromcache(IntegerSetStrategy):
+ return False
+ if strategy is self.space.fromcache(EmptySetStrategy):
+ return False
+ return True
+
+ def unwrap(self, w_item):
+ return self.space.str_w(w_item)
+
+ def wrap(self, item):
+ return self.space.wrap(item)
+
+ def iter(self, w_set):
+ return StringIteratorImplementation(self.space, self, w_set)
+
+class IntegerSetStrategy(AbstractUnwrappedSetStrategy, SetStrategy):
+ erase, unerase = rerased.new_erasing_pair("integer")
+ erase = staticmethod(erase)
+ unerase = staticmethod(unerase)
+
+ def get_empty_storage(self):
+ return self.erase({})
+
+ def get_empty_dict(self):
+ return {}
+
+ def listview_int(self, w_set):
+ return self.unerase(w_set.sstorage).keys()
+
+ def is_correct_type(self, w_key):
+ from pypy.objspace.std.intobject import W_IntObject
+ return type(w_key) is W_IntObject
+
+ def may_contain_equal_elements(self, strategy):
+ if strategy is self.space.fromcache(StringSetStrategy):
+ return False
+ if strategy is self.space.fromcache(EmptySetStrategy):
+ return False
+ return True
+
+ def unwrap(self, w_item):
+ return self.space.int_w(w_item)
+
+ def wrap(self, item):
+ return self.space.wrap(item)
+
+ def iter(self, w_set):
+ return IntegerIteratorImplementation(self.space, self, w_set)
+
+class ObjectSetStrategy(AbstractUnwrappedSetStrategy, SetStrategy):
+ erase, unerase = rerased.new_erasing_pair("object")
+ erase = staticmethod(erase)
+ unerase = staticmethod(unerase)
+
+ def get_empty_storage(self):
+ return self.erase(self.get_empty_dict())
+
+ def get_empty_dict(self):
+ return newset(self.space)
+
+ def is_correct_type(self, w_key):
+ return True
+
+ def may_contain_equal_elements(self, strategy):
+ if strategy is self.space.fromcache(EmptySetStrategy):
+ return False
+ return True
+
+ def unwrap(self, w_item):
+ return w_item
+
+ def wrap(self, item):
+ return item
+
+ def iter(self, w_set):
+ return RDictIteratorImplementation(self.space, self, w_set)
+
+ def update(self, w_set, w_other):
+ d_obj = self.unerase(w_set.sstorage)
+ w_iterator = w_other.iter()
+ while True:
+ w_item = w_iterator.next_entry()
+ if w_item is None:
+ break
+ d_obj[w_item] = None
+
+class IteratorImplementation(object):
+ def __init__(self, space, implementation):
+ self.space = space
+ self.setimplementation = implementation
+ self.len = implementation.length()
+ self.pos = 0
+
+ def next(self):
+ if self.setimplementation is None:
+ return None
+ if self.len != self.setimplementation.length():
+ self.len = -1 # Make this error state sticky
+ raise OperationError(self.space.w_RuntimeError,
+ self.space.wrap("set changed size during iteration"))
+ # look for the next entry
+ if self.pos < self.len:
+ result = self.next_entry()
+ self.pos += 1
+ return result
+ # no more entries
+ self.setimplementation = None
+ return None
+
+ def next_entry(self):
+ """ Purely abstract method
+ """
+ raise NotImplementedError
+
+ def length(self):
+ if self.setimplementation is not None:
+ return self.len - self.pos
+ return 0
+
+class EmptyIteratorImplementation(IteratorImplementation):
+ def next_entry(self):
+ return None
+
+
+class StringIteratorImplementation(IteratorImplementation):
+ def __init__(self, space, strategy, w_set):
+ IteratorImplementation.__init__(self, space, w_set)
+ d = strategy.unerase(w_set.sstorage)
+ self.iterator = d.iterkeys()
+
+ def next_entry(self):
+ for key in self.iterator:
+ return self.space.wrap(key)
+ else:
+ return None
+
+class IntegerIteratorImplementation(IteratorImplementation):
+ #XXX same implementation in dictmultiobject on dictstrategy-branch
+ def __init__(self, space, strategy, dictimplementation):
+ IteratorImplementation.__init__(self, space, dictimplementation)
+ d = strategy.unerase(dictimplementation.sstorage)
+ self.iterator = d.iterkeys()
+
+ def next_entry(self):
+ # note that this 'for' loop only runs once, at most
+ for key in self.iterator:
+ return self.space.wrap(key)
+ else:
+ return None
+
+class RDictIteratorImplementation(IteratorImplementation):
+ def __init__(self, space, strategy, dictimplementation):
+ IteratorImplementation.__init__(self, space, dictimplementation)
+ d = strategy.unerase(dictimplementation.sstorage)
+ self.iterator = d.iterkeys()
+
+ def next_entry(self):
+ # note that this 'for' loop only runs once, at most
+ for w_key in self.iterator:
return w_key
else:
return None
+class W_SetIterObject(W_Object):
+ from pypy.objspace.std.settype import setiter_typedef as typedef
+ # XXX this class should be killed, and the various
+ # iterimplementations should be W_Objects directly.
+
+ def __init__(w_self, space, iterimplementation):
+ w_self.space = space
+ w_self.iterimplementation = iterimplementation
+
registerimplementation(W_SetIterObject)
def iter__SetIterObject(space, w_setiter):
return w_setiter
def next__SetIterObject(space, w_setiter):
- content = w_setiter.content
- if content is not None:
- if w_setiter.len != len(content):
- w_setiter.len = -1 # Make this error state sticky
- raise OperationError(space.w_RuntimeError,
- space.wrap("Set changed size during iteration"))
- # look for the next entry
- w_result = w_setiter.next_entry()
- if w_result is not None:
- w_setiter.pos += 1
- return w_result
- # no more entries
- w_setiter.content = None
+ iterimplementation = w_setiter.iterimplementation
+ w_key = iterimplementation.next()
+ if w_key is not None:
+ return w_key
raise OperationError(space.w_StopIteration, space.w_None)
# XXX __length_hint__()
@@ -116,107 +893,91 @@
def newset(space):
return r_dict(space.eq_w, space.hash_w, force_non_null=True)
-def make_setdata_from_w_iterable(space, w_iterable=None):
- """Return a new r_dict with the content of w_iterable."""
+def set_strategy_and_setdata(space, w_set, w_iterable):
+ from pypy.objspace.std.intobject import W_IntObject
+ if w_iterable is None :
+ w_set.strategy = strategy = space.fromcache(EmptySetStrategy)
+ w_set.sstorage = strategy.get_empty_storage()
+ return
+
if isinstance(w_iterable, W_BaseSetObject):
- return w_iterable.setdata.copy()
- data = newset(space)
- if w_iterable is not None:
- for w_item in space.listview(w_iterable):
- data[w_item] = None
- return data
+ w_set.strategy = w_iterable.strategy
+ w_set.sstorage = w_iterable.get_storage_copy()
+ return
+
+ stringlist = space.listview_str(w_iterable)
+ if stringlist is not None:
+ strategy = space.fromcache(StringSetStrategy)
+ w_set.strategy = strategy
+ w_set.sstorage = strategy.get_storage_from_unwrapped_list(stringlist)
+ return
+
+ intlist = space.listview_int(w_iterable)
+ if intlist is not None:
+ strategy = space.fromcache(IntegerSetStrategy)
+ w_set.strategy = strategy
+ w_set.sstorage = strategy.get_storage_from_unwrapped_list(intlist)
+ return
+
+ iterable_w = space.listview(w_iterable)
+
+ if len(iterable_w) == 0:
+ w_set.strategy = strategy = space.fromcache(EmptySetStrategy)
+ w_set.sstorage = strategy.get_empty_storage()
+ return
+
+ _pick_correct_strategy(space, w_set, iterable_w)
+
+def _pick_correct_strategy(space, w_set, iterable_w):
+ # check for integers
+ for w_item in iterable_w:
+ if type(w_item) is not W_IntObject:
+ break
+ else:
+ w_set.strategy = space.fromcache(IntegerSetStrategy)
+ w_set.sstorage = w_set.strategy.get_storage_from_list(iterable_w)
+ return
+
+ # check for strings
+ for w_item in iterable_w:
+ if type(w_item) is not W_StringObject:
+ break
+ else:
+ w_set.strategy = space.fromcache(StringSetStrategy)
+ w_set.sstorage = w_set.strategy.get_storage_from_list(iterable_w)
+ return
+
+ w_set.strategy = space.fromcache(ObjectSetStrategy)
+ w_set.sstorage = w_set.strategy.get_storage_from_list(iterable_w)
def _initialize_set(space, w_obj, w_iterable=None):
- w_obj.setdata.clear()
- if w_iterable is not None:
- w_obj.setdata = make_setdata_from_w_iterable(space, w_iterable)
+ w_obj.clear()
+ set_strategy_and_setdata(space, w_obj, w_iterable)
def _convert_set_to_frozenset(space, w_obj):
- if space.isinstance_w(w_obj, space.w_set):
- return W_FrozensetObject(space,
- make_setdata_from_w_iterable(space, w_obj))
+ if isinstance(w_obj, W_SetObject):
+ w_frozen = W_FrozensetObject(space, None)
+ w_frozen.strategy = w_obj.strategy
+ w_frozen.sstorage = w_obj.sstorage
+ return w_frozen
+ elif space.isinstance_w(w_obj, space.w_set):
+ w_frz = space.allocate_instance(W_FrozensetObject, space.w_frozenset)
+ W_FrozensetObject.__init__(w_frz, space, w_obj)
+ return w_frz
else:
return None
-# helper functions for set operation on dicts
-
-def _is_eq(ld, rd):
- if len(ld) != len(rd):
- return False
- for w_key in ld:
- if w_key not in rd:
- return False
- return True
-
-def _difference_dict(space, ld, rd):
- result = newset(space)
- for w_key in ld:
- if w_key not in rd:
- result[w_key] = None
- return result
-
-def _difference_dict_update(space, ld, rd):
- if ld is rd:
- ld.clear() # for the case 'a.difference_update(a)'
- else:
- for w_key in rd:
- try:
- del ld[w_key]
- except KeyError:
- pass
-
-def _intersection_dict(space, ld, rd):
- result = newset(space)
- if len(ld) > len(rd):
- ld, rd = rd, ld # loop over the smaller dict
- for w_key in ld:
- if w_key in rd:
- result[w_key] = None
- return result
-
-def _isdisjoint_dict(ld, rd):
- if len(ld) > len(rd):
- ld, rd = rd, ld # loop over the smaller dict
- for w_key in ld:
- if w_key in rd:
- return False
- return True
-
-def _symmetric_difference_dict(space, ld, rd):
- result = newset(space)
- for w_key in ld:
- if w_key not in rd:
- result[w_key] = None
- for w_key in rd:
- if w_key not in ld:
- result[w_key] = None
- return result
-
-def _issubset_dict(ldict, rdict):
- if len(ldict) > len(rdict):
- return False
-
- for w_key in ldict:
- if w_key not in rdict:
- return False
- return True
-
-
-#end helper functions
-
def set_update__Set(space, w_left, others_w):
"""Update a set with the union of itself and another."""
- ld = w_left.setdata
for w_other in others_w:
if isinstance(w_other, W_BaseSetObject):
- ld.update(w_other.setdata) # optimization only
+ w_left.update(w_other) # optimization only
else:
for w_key in space.listview(w_other):
- ld[w_key] = None
+ w_left.add(w_key)
def inplace_or__Set_Set(space, w_left, w_other):
- ld, rd = w_left.setdata, w_other.setdata
- ld.update(rd)
+ w_left.update(w_other)
return w_left
inplace_or__Set_Frozenset = inplace_or__Set_Set
@@ -226,10 +987,10 @@
This has no effect if the element is already present.
"""
- w_left.setdata[w_other] = None
+ w_left.add(w_other)
def set_copy__Set(space, w_set):
- return w_set._newobj(space, w_set.setdata.copy())
+ return w_set.copy_real()
def frozenset_copy__Frozenset(space, w_left):
if type(w_left) is W_FrozensetObject:
@@ -238,63 +999,51 @@
return set_copy__Set(space, w_left)
def set_clear__Set(space, w_left):
- w_left.setdata.clear()
+ w_left.clear()
def sub__Set_Set(space, w_left, w_other):
- ld, rd = w_left.setdata, w_other.setdata
- new_ld = _difference_dict(space, ld, rd)
- return w_left._newobj(space, new_ld)
+ return w_left.difference(w_other)
sub__Set_Frozenset = sub__Set_Set
sub__Frozenset_Set = sub__Set_Set
sub__Frozenset_Frozenset = sub__Set_Set
def set_difference__Set(space, w_left, others_w):
- result = w_left.setdata
- if len(others_w) == 0:
- result = result.copy()
- for w_other in others_w:
- if isinstance(w_other, W_BaseSetObject):
- rd = w_other.setdata # optimization only
- else:
- rd = make_setdata_from_w_iterable(space, w_other)
- result = _difference_dict(space, result, rd)
- return w_left._newobj(space, result)
+ result = w_left.copy_real()
+ set_difference_update__Set(space, result, others_w)
+ return result
frozenset_difference__Frozenset = set_difference__Set
def set_difference_update__Set(space, w_left, others_w):
- ld = w_left.setdata
for w_other in others_w:
if isinstance(w_other, W_BaseSetObject):
# optimization only
- _difference_dict_update(space, ld, w_other.setdata)
+ w_left.difference_update(w_other)
else:
- for w_key in space.listview(w_other):
- try:
- del ld[w_key]
- except KeyError:
- pass
+ w_other_as_set = w_left._newobj(space, w_other)
+ w_left.difference_update(w_other_as_set)
def inplace_sub__Set_Set(space, w_left, w_other):
- ld, rd = w_left.setdata, w_other.setdata
- _difference_dict_update(space, ld, rd)
+ w_left.difference_update(w_other)
return w_left
inplace_sub__Set_Frozenset = inplace_sub__Set_Set
def eq__Set_Set(space, w_left, w_other):
# optimization only (the general case is eq__Set_settypedef)
- return space.wrap(_is_eq(w_left.setdata, w_other.setdata))
+ return space.wrap(w_left.equals(w_other))
eq__Set_Frozenset = eq__Set_Set
eq__Frozenset_Frozenset = eq__Set_Set
eq__Frozenset_Set = eq__Set_Set
def eq__Set_settypedef(space, w_left, w_other):
- rd = make_setdata_from_w_iterable(space, w_other)
- return space.wrap(_is_eq(w_left.setdata, rd))
+ # tested in test_buildinshortcut.py
+ #XXX do not make new setobject here
+ w_other_as_set = w_left._newobj(space, w_other)
+ return space.wrap(w_left.equals(w_other_as_set))
eq__Set_frozensettypedef = eq__Set_settypedef
eq__Frozenset_settypedef = eq__Set_settypedef
@@ -308,15 +1057,16 @@
eq__Frozenset_ANY = eq__Set_ANY
def ne__Set_Set(space, w_left, w_other):
- return space.wrap(not _is_eq(w_left.setdata, w_other.setdata))
+ return space.wrap(not w_left.equals(w_other))
ne__Set_Frozenset = ne__Set_Set
ne__Frozenset_Frozenset = ne__Set_Set
ne__Frozenset_Set = ne__Set_Set
def ne__Set_settypedef(space, w_left, w_other):
- rd = make_setdata_from_w_iterable(space, w_other)
- return space.wrap(not _is_eq(w_left.setdata, rd))
+ #XXX this is not tested
+ w_other_as_set = w_left._newobj(space, w_other)
+ return space.wrap(not w_left.equals(w_other_as_set))
ne__Set_frozensettypedef = ne__Set_settypedef
ne__Frozenset_settypedef = ne__Set_settypedef
@@ -331,12 +1081,12 @@
def contains__Set_ANY(space, w_left, w_other):
try:
- return space.newbool(w_other in w_left.setdata)
+ return space.newbool(w_left.has_key(w_other))
except OperationError, e:
if e.match(space, space.w_TypeError):
w_f = _convert_set_to_frozenset(space, w_other)
if w_f is not None:
- return space.newbool(w_f in w_left.setdata)
+ return space.newbool(w_left.has_key(w_f))
raise
contains__Frozenset_ANY = contains__Set_ANY
@@ -345,19 +1095,23 @@
# optimization only (the general case works too)
if space.is_w(w_left, w_other):
return space.w_True
- ld, rd = w_left.setdata, w_other.setdata
- return space.wrap(_issubset_dict(ld, rd))
+ if w_left.length() > w_other.length():
+ return space.w_False
+ return space.wrap(w_left.issubset(w_other))
set_issubset__Set_Frozenset = set_issubset__Set_Set
frozenset_issubset__Frozenset_Set = set_issubset__Set_Set
frozenset_issubset__Frozenset_Frozenset = set_issubset__Set_Set
def set_issubset__Set_ANY(space, w_left, w_other):
- if space.is_w(w_left, w_other):
- return space.w_True
+ # not checking whether w_left is w_other here, because if that were the
+ # case the more precise multimethod would have applied.
- ld, rd = w_left.setdata, make_setdata_from_w_iterable(space, w_other)
- return space.wrap(_issubset_dict(ld, rd))
+ w_other_as_set = w_left._newobj(space, w_other)
+
+ if w_left.length() > w_other_as_set.length():
+ return space.w_False
+ return space.wrap(w_left.issubset(w_other_as_set))
frozenset_issubset__Frozenset_ANY = set_issubset__Set_ANY
@@ -370,9 +1124,9 @@
# optimization only (the general case works too)
if space.is_w(w_left, w_other):
return space.w_True
-
- ld, rd = w_left.setdata, w_other.setdata
- return space.wrap(_issubset_dict(rd, ld))
+ if w_left.length() < w_other.length():
+ return space.w_False
+ return space.wrap(w_other.issubset(w_left))
set_issuperset__Set_Frozenset = set_issuperset__Set_Set
set_issuperset__Frozenset_Set = set_issuperset__Set_Set
@@ -382,8 +1136,11 @@
if space.is_w(w_left, w_other):
return space.w_True
- ld, rd = w_left.setdata, make_setdata_from_w_iterable(space, w_other)
- return space.wrap(_issubset_dict(rd, ld))
+ w_other_as_set = w_left._newobj(space, w_other)
+
+ if w_left.length() < w_other_as_set.length():
+ return space.w_False
+ return space.wrap(w_other_as_set.issubset(w_left))
frozenset_issuperset__Frozenset_ANY = set_issuperset__Set_ANY
@@ -395,7 +1152,7 @@
# automatic registration of "lt(x, y)" as "not ge(y, x)" would not give the
# correct answer here!
def lt__Set_Set(space, w_left, w_other):
- if len(w_left.setdata) >= len(w_other.setdata):
+ if w_left.length() >= w_other.length():
return space.w_False
else:
return le__Set_Set(space, w_left, w_other)
@@ -405,7 +1162,7 @@
lt__Frozenset_Frozenset = lt__Set_Set
def gt__Set_Set(space, w_left, w_other):
- if len(w_left.setdata) <= len(w_other.setdata):
+ if w_left.length() <= w_other.length():
return space.w_False
else:
return ge__Set_Set(space, w_left, w_other)
@@ -421,26 +1178,19 @@
Returns True if successfully removed.
"""
try:
- del w_left.setdata[w_item]
- return True
- except KeyError:
- return False
+ deleted = w_left.remove(w_item)
except OperationError, e:
if not e.match(space, space.w_TypeError):
raise
- w_f = _convert_set_to_frozenset(space, w_item)
- if w_f is None:
- raise
+ else:
+ w_f = _convert_set_to_frozenset(space, w_item)
+ if w_f is None:
+ raise
+ deleted = w_left.remove(w_f)
- try:
- del w_left.setdata[w_f]
- return True
- except KeyError:
- return False
- except OperationError, e:
- if not e.match(space, space.w_TypeError):
- raise
- return False
+ if w_left.length() == 0:
+ w_left.switch_to_empty_strategy()
+ return deleted
def set_discard__Set_ANY(space, w_left, w_item):
_discard_from_set(space, w_left, w_item)
@@ -454,8 +1204,12 @@
if w_set.hash != 0:
return space.wrap(w_set.hash)
hash = r_uint(1927868237)
- hash *= r_uint(len(w_set.setdata) + 1)
- for w_item in w_set.setdata:
+ hash *= r_uint(w_set.length() + 1)
+ w_iterator = w_set.iter()
+ while True:
+ w_item = w_iterator.next_entry()
+ if w_item is None:
+ break
h = space.hash_w(w_item)
value = (r_uint(h ^ (h << 16) ^ 89869747) * multi)
hash = hash ^ value
@@ -468,71 +1222,75 @@
return space.wrap(hash)
def set_pop__Set(space, w_left):
- try:
- w_key, _ = w_left.setdata.popitem()
- except KeyError:
- raise OperationError(space.w_KeyError,
- space.wrap('pop from an empty set'))
- return w_key
+ return w_left.popitem()
def and__Set_Set(space, w_left, w_other):
- ld, rd = w_left.setdata, w_other.setdata
- new_ld = _intersection_dict(space, ld, rd)
- return w_left._newobj(space, new_ld)
+ new_set = w_left.intersect(w_other)
+ return new_set
and__Set_Frozenset = and__Set_Set
and__Frozenset_Set = and__Set_Set
and__Frozenset_Frozenset = and__Set_Set
-def _intersection_multiple(space, w_left, others_w):
- result = w_left.setdata
- for w_other in others_w:
+def set_intersection__Set(space, w_left, others_w):
+ #XXX find smarter implementations
+ others_w = [w_left] + others_w
+
+ # find smallest set in others_w to reduce comparisons
+ startindex, startlength = 0, -1
+ for i in range(len(others_w)):
+ w_other = others_w[i]
+ try:
+ length = space.int_w(space.len(w_other))
+ except OperationError, e:
+ if (e.match(space, space.w_TypeError) or
+ e.match(space, space.w_AttributeError)):
+ continue
+ raise
+
+ if startlength == -1 or length < startlength:
+ startindex = i
+ startlength = length
+
+ others_w[startindex], others_w[0] = others_w[0], others_w[startindex]
+
+ result = w_left._newobj(space, others_w[0])
+ for i in range(1,len(others_w)):
+ w_other = others_w[i]
if isinstance(w_other, W_BaseSetObject):
# optimization only
- result = _intersection_dict(space, result, w_other.setdata)
+ result.intersect_update(w_other)
else:
- result2 = newset(space)
- for w_key in space.listview(w_other):
- if w_key in result:
- result2[w_key] = None
- result = result2
+ w_other_as_set = w_left._newobj(space, w_other)
+ result.intersect_update(w_other_as_set)
return result
-def set_intersection__Set(space, w_left, others_w):
- if len(others_w) == 0:
- result = w_left.setdata.copy()
- else:
- result = _intersection_multiple(space, w_left, others_w)
- return w_left._newobj(space, result)
-
frozenset_intersection__Frozenset = set_intersection__Set
def set_intersection_update__Set(space, w_left, others_w):
- result = _intersection_multiple(space, w_left, others_w)
- w_left.setdata = result
+ result = set_intersection__Set(space, w_left, others_w)
+ w_left.strategy = result.strategy
+ w_left.sstorage = result.sstorage
+ return
def inplace_and__Set_Set(space, w_left, w_other):
- ld, rd = w_left.setdata, w_other.setdata
- new_ld = _intersection_dict(space, ld, rd)
- w_left.setdata = new_ld
+ w_left.intersect_update(w_other)
return w_left
inplace_and__Set_Frozenset = inplace_and__Set_Set
def set_isdisjoint__Set_Set(space, w_left, w_other):
# optimization only (the general case works too)
- ld, rd = w_left.setdata, w_other.setdata
- disjoint = _isdisjoint_dict(ld, rd)
- return space.newbool(disjoint)
+ return space.newbool(w_left.isdisjoint(w_other))
set_isdisjoint__Set_Frozenset = set_isdisjoint__Set_Set
set_isdisjoint__Frozenset_Frozenset = set_isdisjoint__Set_Set
set_isdisjoint__Frozenset_Set = set_isdisjoint__Set_Set
def set_isdisjoint__Set_ANY(space, w_left, w_other):
- ld = w_left.setdata
+ #XXX may be optimized when other strategies are added
for w_key in space.listview(w_other):
- if w_key in ld:
+ if w_left.has_key(w_key):
return space.w_False
return space.w_True
@@ -540,9 +1298,8 @@
def set_symmetric_difference__Set_Set(space, w_left, w_other):
# optimization only (the general case works too)
- ld, rd = w_left.setdata, w_other.setdata
- new_ld = _symmetric_difference_dict(space, ld, rd)
- return w_left._newobj(space, new_ld)
+ w_result = w_left.symmetric_difference(w_other)
+ return w_result
set_symmetric_difference__Set_Frozenset = set_symmetric_difference__Set_Set
set_symmetric_difference__Frozenset_Set = set_symmetric_difference__Set_Set
@@ -556,26 +1313,23 @@
def set_symmetric_difference__Set_ANY(space, w_left, w_other):
- ld, rd = w_left.setdata, make_setdata_from_w_iterable(space, w_other)
- new_ld = _symmetric_difference_dict(space, ld, rd)
- return w_left._newobj(space, new_ld)
+ w_other_as_set = w_left._newobj(space, w_other)
+ w_result = w_left.symmetric_difference(w_other_as_set)
+ return w_result
frozenset_symmetric_difference__Frozenset_ANY = \
set_symmetric_difference__Set_ANY
def set_symmetric_difference_update__Set_Set(space, w_left, w_other):
# optimization only (the general case works too)
- ld, rd = w_left.setdata, w_other.setdata
- new_ld = _symmetric_difference_dict(space, ld, rd)
- w_left.setdata = new_ld
+ w_left.symmetric_difference_update(w_other)
set_symmetric_difference_update__Set_Frozenset = \
set_symmetric_difference_update__Set_Set
def set_symmetric_difference_update__Set_ANY(space, w_left, w_other):
- ld, rd = w_left.setdata, make_setdata_from_w_iterable(space, w_other)
- new_ld = _symmetric_difference_dict(space, ld, rd)
- w_left.setdata = new_ld
+ w_other_as_set = w_left._newobj(space, w_other)
+ w_left.symmetric_difference_update(w_other_as_set)
def inplace_xor__Set_Set(space, w_left, w_other):
set_symmetric_difference_update__Set_Set(space, w_left, w_other)
@@ -584,34 +1338,33 @@
inplace_xor__Set_Frozenset = inplace_xor__Set_Set
def or__Set_Set(space, w_left, w_other):
- ld, rd = w_left.setdata, w_other.setdata
- result = ld.copy()
- result.update(rd)
- return w_left._newobj(space, result)
+ w_copy = w_left.copy_real()
+ w_copy.update(w_other)
+ return w_copy
or__Set_Frozenset = or__Set_Set
or__Frozenset_Set = or__Set_Set
or__Frozenset_Frozenset = or__Set_Set
def set_union__Set(space, w_left, others_w):
- result = w_left.setdata.copy()
+ result = w_left.copy_real()
for w_other in others_w:
if isinstance(w_other, W_BaseSetObject):
- result.update(w_other.setdata) # optimization only
+ result.update(w_other) # optimization only
else:
for w_key in space.listview(w_other):
- result[w_key] = None
- return w_left._newobj(space, result)
+ result.add(w_key)
+ return result
frozenset_union__Frozenset = set_union__Set
def len__Set(space, w_left):
- return space.newint(len(w_left.setdata))
+ return space.newint(w_left.length())
len__Frozenset = len__Set
def iter__Set(space, w_left):
- return W_SetIterObject(w_left.setdata)
+ return W_SetIterObject(space, w_left.iter())
iter__Frozenset = iter__Set
diff --git a/pypy/objspace/std/settype.py b/pypy/objspace/std/settype.py
--- a/pypy/objspace/std/settype.py
+++ b/pypy/objspace/std/settype.py
@@ -68,7 +68,7 @@
def descr__new__(space, w_settype, __args__):
from pypy.objspace.std.setobject import W_SetObject, newset
w_obj = space.allocate_instance(W_SetObject, w_settype)
- W_SetObject.__init__(w_obj, space, newset(space))
+ W_SetObject.__init__(w_obj, space)
return w_obj
set_typedef = StdTypeDef("set",
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
@@ -69,6 +69,14 @@
def str_w(w_self, space):
return w_self._value
+ def listview_str(w_self):
+ return _create_list_from_string(w_self._value)
+
+def _create_list_from_string(value):
+ # need this helper function to allow the jit to look inside and inline
+ # listview_str
+ return [s for s in value]
+
registerimplementation(W_StringObject)
W_StringObject.EMPTY = W_StringObject('')
diff --git a/pypy/objspace/std/test/test_builtinshortcut.py b/pypy/objspace/std/test/test_builtinshortcut.py
--- a/pypy/objspace/std/test/test_builtinshortcut.py
+++ b/pypy/objspace/std/test/test_builtinshortcut.py
@@ -85,6 +85,20 @@
def setup_class(cls):
from pypy import conftest
cls.space = conftest.gettestobjspace(**WITH_BUILTINSHORTCUT)
+ w_fakeint = cls.space.appexec([], """():
+ class FakeInt(object):
+ def __init__(self, value):
+ self.value = value
+ def __hash__(self):
+ return hash(self.value)
+
+ def __eq__(self, other):
+ if other == self.value:
+ return True
+ return False
+ return FakeInt
+ """)
+ cls.w_FakeInt = w_fakeint
class AppTestString(test_stringobject.AppTestStringObject):
def setup_class(cls):
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
@@ -131,6 +131,45 @@
assert self.space.eq_w(space.call_function(get, w("33")), w(None))
assert self.space.eq_w(space.call_function(get, w("33"), w(44)), w(44))
+ def test_fromkeys_fastpath(self):
+ space = self.space
+ w = space.wrap
+
+ w_l = self.space.newlist([w("a"),w("b")])
+ w_l.getitems = None
+ w_d = space.call_method(space.w_dict, "fromkeys", w_l)
+
+ assert space.eq_w(w_d.getitem_str("a"), space.w_None)
+ assert space.eq_w(w_d.getitem_str("b"), space.w_None)
+
+ def test_listview_str_dict(self):
+ w = self.space.wrap
+
+ w_d = self.space.newdict()
+ w_d.initialize_content([(w("a"), w(1)), (w("b"), w(2))])
+
+ assert self.space.listview_str(w_d) == ["a", "b"]
+
+ def test_listview_int_dict(self):
+ w = self.space.wrap
+ w_d = self.space.newdict()
+ w_d.initialize_content([(w(1), w("a")), (w(2), w("b"))])
+
+ assert self.space.listview_int(w_d) == [1, 2]
+
+ def test_keys_on_string_int_dict(self):
+ w = self.space.wrap
+ w_d = self.space.newdict()
+ w_d.initialize_content([(w(1), w("a")), (w(2), w("b"))])
+
+ w_l = self.space.call_method(w_d, "keys")
+ assert sorted(self.space.listview_int(w_l)) == [1,2]
+
+ w_d = self.space.newdict()
+ w_d.initialize_content([(w("a"), w(1)), (w("b"), w(6))])
+
+ w_l = self.space.call_method(w_d, "keys")
+ assert sorted(self.space.listview_str(w_l)) == ["a", "b"]
class AppTest_DictObject:
def setup_class(cls):
@@ -793,7 +832,9 @@
return x == y
eq_w = eq
def newlist(self, l):
- return []
+ return l
+ def newlist_str(self, l):
+ return l
DictObjectCls = W_DictMultiObject
def type(self, w_obj):
if isinstance(w_obj, FakeString):
@@ -933,7 +974,7 @@
def test_keys(self):
self.fill_impl()
- keys = self.impl.keys()
+ keys = self.impl.w_keys() # wrapped lists = lists in the fake space
keys.sort()
assert keys == [self.string, self.string2]
self.check_not_devolved()
@@ -1011,8 +1052,8 @@
d.setitem("s", 12)
d.delitem(F())
- assert "s" not in d.keys()
- assert F() not in d.keys()
+ assert "s" not in d.w_keys()
+ assert F() not in d.w_keys()
class TestStrDictImplementation(BaseTestRDictImplementation):
StrategyClass = StringDictStrategy
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
@@ -486,6 +486,14 @@
list.__init__(l, ['a', 'b', 'c'])
assert l is l0
assert l == ['a', 'b', 'c']
+ list.__init__(l)
+ assert l == []
+
+ def test_explicit_new_init_more_cases(self):
+ for assignment in [[], (), [3], ["foo"]]:
+ l = [1, 2]
+ l.__init__(assignment)
+ assert l == list(assignment)
def test_extend_list(self):
l = l0 = [1]
@@ -1173,6 +1181,20 @@
assert l == []
assert list(g) == []
+ def test_uses_custom_iterator(self):
+ # obscure corner case: space.listview*() must not shortcut subclasses
+ # of dicts, because the OrderedDict in the stdlib relies on this.
+ # we extend the use case to lists and sets, i.e. all types that have
+ # strategies, to avoid surprizes depending on the strategy.
+ for base, arg in [(list, []), (list, [5]), (list, ['x']),
+ (set, []), (set, [5]), (set, ['x']),
+ (dict, []), (dict, [(5,6)]), (dict, [('x',7)])]:
+ print base, arg
+ class SubClass(base):
+ def __iter__(self):
+ return iter("foobar")
+ assert list(SubClass(arg)) == ['f', 'o', 'o', 'b', 'a', 'r']
+
class AppTestForRangeLists(AppTestW_ListObject):
def setup_class(cls):
diff --git a/pypy/objspace/std/test/test_liststrategies.py b/pypy/objspace/std/test/test_liststrategies.py
--- a/pypy/objspace/std/test/test_liststrategies.py
+++ b/pypy/objspace/std/test/test_liststrategies.py
@@ -420,7 +420,7 @@
def test_listview_str(self):
space = self.space
- assert space.listview_str(space.wrap("a")) is None
+ assert space.listview_str(space.wrap(1)) == None
w_l = self.space.newlist([self.space.wrap('a'), self.space.wrap('b')])
assert space.listview_str(w_l) == ["a", "b"]
@@ -463,6 +463,44 @@
w_res = listobject.list_pop__List_ANY(space, w_l, space.w_None) # does not crash
assert space.unwrap(w_res) == 3
+ def test_create_list_from_set(self):
+ from pypy.objspace.std.setobject import W_SetObject
+ from pypy.objspace.std.setobject import _initialize_set
+
+ space = self.space
+ w = space.wrap
+
+ w_l = W_ListObject(space, [space.wrap(1), space.wrap(2), space.wrap(3)])
+
+ w_set = W_SetObject(self.space)
+ _initialize_set(self.space, w_set, w_l)
+ w_set.iter = None # make sure fast path is used
+
+ w_l2 = W_ListObject(space, [])
+ space.call_method(w_l2, "__init__", w_set)
+
+ w_l2.sort(False)
+ assert space.eq_w(w_l, w_l2)
+
+ w_l = W_ListObject(space, [space.wrap("a"), space.wrap("b"), space.wrap("c")])
+ _initialize_set(self.space, w_set, w_l)
+
+ space.call_method(w_l2, "__init__", w_set)
+
+ w_l2.sort(False)
+ assert space.eq_w(w_l, w_l2)
+
+
+ def test_listview_str_list(self):
+ space = self.space
+ w_l = W_ListObject(space, [space.wrap("a"), space.wrap("b")])
+ assert self.space.listview_str(w_l) == ["a", "b"]
+
+ def test_listview_int_list(self):
+ space = self.space
+ w_l = W_ListObject(space, [space.wrap(1), space.wrap(2), space.wrap(3)])
+ assert self.space.listview_int(w_l) == [1, 2, 3]
+
class TestW_ListStrategiesDisabled:
def setup_class(cls):
diff --git a/pypy/objspace/std/test/test_setobject.py b/pypy/objspace/std/test/test_setobject.py
--- a/pypy/objspace/std/test/test_setobject.py
+++ b/pypy/objspace/std/test/test_setobject.py
@@ -8,12 +8,14 @@
is not too wrong.
"""
import py.test
-from pypy.objspace.std.setobject import W_SetObject, W_FrozensetObject
+from pypy.objspace.std.setobject import W_SetObject, W_FrozensetObject, IntegerSetStrategy
from pypy.objspace.std.setobject import _initialize_set
-from pypy.objspace.std.setobject import newset, make_setdata_from_w_iterable
+from pypy.objspace.std.setobject import newset
from pypy.objspace.std.setobject import and__Set_Set
from pypy.objspace.std.setobject import set_intersection__Set
from pypy.objspace.std.setobject import eq__Set_Set
+from pypy.conftest import gettestobjspace
+from pypy.objspace.std.listobject import W_ListObject
letters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
@@ -29,12 +31,11 @@
self.false = self.space.w_False
def test_and(self):
- s = W_SetObject(self.space, newset(self.space))
+ s = W_SetObject(self.space)
_initialize_set(self.space, s, self.word)
- t0 = W_SetObject(self.space, newset(self.space))
+ t0 = W_SetObject(self.space)
_initialize_set(self.space, t0, self.otherword)
- t1 = W_FrozensetObject(self.space,
- make_setdata_from_w_iterable(self.space, self.otherword))
+ t1 = W_FrozensetObject(self.space, self.otherword)
r0 = and__Set_Set(self.space, s, t0)
r1 = and__Set_Set(self.space, s, t1)
assert eq__Set_Set(self.space, r0, r1) == self.true
@@ -42,9 +43,9 @@
assert eq__Set_Set(self.space, r0, sr) == self.true
def test_compare(self):
- s = W_SetObject(self.space, newset(self.space))
+ s = W_SetObject(self.space)
_initialize_set(self.space, s, self.word)
- t = W_SetObject(self.space, newset(self.space))
+ t = W_SetObject(self.space)
_initialize_set(self.space, t, self.word)
assert self.space.eq_w(s,t)
u = self.space.wrap(set('simsalabim'))
@@ -54,7 +55,247 @@
s = self.space.newset()
assert self.space.str_w(self.space.repr(s)) == 'set([])'
+ def test_intersection_order(self):
+ # theses tests make sure that intersection is done in the correct order
+ # (smallest first)
+ space = self.space
+ a = W_SetObject(self.space)
+ _initialize_set(self.space, a, self.space.wrap("abcdefg"))
+ a.intersect = None
+
+ b = W_SetObject(self.space)
+ _initialize_set(self.space, b, self.space.wrap("abc"))
+
+ result = set_intersection__Set(space, a, [b])
+ assert space.is_true(self.space.eq(result, W_SetObject(space, self.space.wrap("abc"))))
+
+ c = W_SetObject(self.space)
+ _initialize_set(self.space, c, self.space.wrap("e"))
+
+ d = W_SetObject(self.space)
+ _initialize_set(self.space, d, self.space.wrap("ab"))
+
+ # if ordering works correct we should start with set e
+ a.get_storage_copy = None
+ b.get_storage_copy = None
+ d.get_storage_copy = None
+
+ result = set_intersection__Set(space, a, [d,c,b])
+ assert space.is_true(self.space.eq(result, W_SetObject(space, self.space.wrap(""))))
+
+ def test_create_set_from_list(self):
+ from pypy.objspace.std.setobject import ObjectSetStrategy, StringSetStrategy
+ from pypy.objspace.std.floatobject import W_FloatObject
+ from pypy.objspace.std.model import W_Object
+
+ w = self.space.wrap
+ intstr = self.space.fromcache(IntegerSetStrategy)
+ tmp_func = intstr.get_storage_from_list
+ # test if get_storage_from_list is no longer used
+ intstr.get_storage_from_list = None
+
+ w_list = W_ListObject(self.space, [w(1), w(2), w(3)])
+ w_set = W_SetObject(self.space)
+ _initialize_set(self.space, w_set, w_list)
+ assert w_set.strategy is intstr
+ assert intstr.unerase(w_set.sstorage) == {1:None, 2:None, 3:None}
+
+ w_list = W_ListObject(self.space, [w("1"), w("2"), w("3")])
+ w_set = W_SetObject(self.space)
+ _initialize_set(self.space, w_set, w_list)
+ assert w_set.strategy is self.space.fromcache(StringSetStrategy)
+ assert w_set.strategy.unerase(w_set.sstorage) == {"1":None, "2":None, "3":None}
+
+ w_list = W_ListObject(self.space, [w("1"), w(2), w("3")])
+ w_set = W_SetObject(self.space)
+ _initialize_set(self.space, w_set, w_list)
+ assert w_set.strategy is self.space.fromcache(ObjectSetStrategy)
+ for item in w_set.strategy.unerase(w_set.sstorage):
+ assert isinstance(item, W_Object)
+
+ w_list = W_ListObject(self.space, [w(1.0), w(2.0), w(3.0)])
+ w_set = W_SetObject(self.space)
+ _initialize_set(self.space, w_set, w_list)
+ assert w_set.strategy is self.space.fromcache(ObjectSetStrategy)
+ for item in w_set.strategy.unerase(w_set.sstorage):
+ assert isinstance(item, W_FloatObject)
+
+ # changed cached object, need to change it back for other tests to pass
+ intstr.get_storage_from_list = tmp_func
+
+ def test_listview_str_int_on_set(self):
+ w = self.space.wrap
+
+ w_a = W_SetObject(self.space)
+ _initialize_set(self.space, w_a, w("abcdefg"))
+ assert sorted(self.space.listview_str(w_a)) == list("abcdefg")
+ assert self.space.listview_int(w_a) is None
+
+ w_b = W_SetObject(self.space)
+ _initialize_set(self.space, w_b, self.space.newlist([w(1),w(2),w(3),w(4),w(5)]))
+ assert sorted(self.space.listview_int(w_b)) == [1,2,3,4,5]
+ assert self.space.listview_str(w_b) is None
+
class AppTestAppSetTest:
+
+ def setup_class(self):
+ self.space = gettestobjspace()
+ w_fakeint = self.space.appexec([], """():
+ class FakeInt(object):
+ def __init__(self, value):
+ self.value = value
+ def __hash__(self):
+ return hash(self.value)
+
+ def __eq__(self, other):
+ if other == self.value:
+ return True
+ return False
+ return FakeInt
+ """)
+ self.w_FakeInt = w_fakeint
+
+ def test_fakeint(self):
+ f1 = self.FakeInt(4)
+ assert f1 == 4
+ assert hash(f1) == hash(4)
+
+ def test_simple(self):
+ a = set([1,2,3])
+ b = set()
+ b.add(4)
+ c = a.union(b)
+ assert c == set([1,2,3,4])
+
+ def test_generator(self):
+ def foo():
+ for i in [1,2,3,4,5]:
+ yield i
+ b = set(foo())
+ assert b == set([1,2,3,4,5])
+
+ a = set(x for x in [1,2,3])
+ assert a == set([1,2,3])
+
+ def test_generator2(self):
+ def foo():
+ for i in [1,2,3]:
+ yield i
+ class A(set):
+ pass
+ a = A([1,2,3,4,5])
+ b = a.difference(foo())
+ assert b == set([4,5])
+
+ def test_or(self):
+ a = set([0,1,2])
+ b = a | set([1,2,3])
+ assert b == set([0,1,2,3])
+
+ # test inplace or
+ a |= set([1,2,3])
+ assert a == b
+
+ def test_clear(self):
+ a = set([1,2,3])
+ a.clear()
+ assert a == set()
+
+ def test_sub(self):
+ a = set([1,2,3,4,5])
+ b = set([2,3,4])
+ a - b == [1,5]
+ a.__sub__(b) == [1,5]
+
+ #inplace sub
+ a = set([1,2,3,4])
+ b = set([1,4])
+ a -= b
+ assert a == set([2,3])
+
+ def test_issubset(self):
+ a = set([1,2,3,4])
+ b = set([2,3])
+ assert b.issubset(a)
+ c = [1,2,3,4]
+ assert b.issubset(c)
+
+ a = set([1,2,3,4])
+ b = set(['1','2'])
+ assert not b.issubset(a)
+
+ def test_issuperset(self):
+ a = set([1,2,3,4])
+ b = set([2,3])
+ assert a.issuperset(b)
+ c = [2,3]
+ assert a.issuperset(c)
+
+ c = [1,1,1,1,1]
+ assert a.issuperset(c)
+ assert set([1,1,1,1,1]).issubset(a)
+
+ a = set([1,2,3])
+ assert a.issuperset(a)
+ assert not a.issuperset(set([1,2,3,4,5]))
+
+ def test_inplace_and(test):
+ a = set([1,2,3,4])
+ b = set([0,2,3,5,6])
+ a &= b
+ assert a == set([2,3])
+
+ def test_discard_remove(self):
+ a = set([1,2,3,4,5])
+ a.remove(1)
+ assert a == set([2,3,4,5])
+ a.discard(2)
+ assert a == set([3,4,5])
+
+ raises(KeyError, "a.remove(6)")
+
+ def test_pop(self):
+ b = set()
+ raises(KeyError, "b.pop()")
+
+ a = set([1,2,3,4,5])
+ for i in xrange(5):
+ a.pop()
+ assert a == set()
+ raises(KeyError, "a.pop()")
+
+ def test_symmetric_difference(self):
+ a = set([1,2,3])
+ b = set([3,4,5])
+ c = a.symmetric_difference(b)
+ assert c == set([1,2,4,5])
+
+ a = set([1,2,3])
+ b = [3,4,5]
+ c = a.symmetric_difference(b)
+ assert c == set([1,2,4,5])
+
+ a = set([1,2,3])
+ b = set('abc')
+ c = a.symmetric_difference(b)
+ assert c == set([1,2,3,'a','b','c'])
+
+ def test_symmetric_difference_update(self):
+ a = set([1,2,3])
+ b = set([3,4,5])
+ a.symmetric_difference_update(b)
+ assert a == set([1,2,4,5])
+
+ a = set([1,2,3])
+ b = [3,4,5]
+ a.symmetric_difference_update(b)
+ assert a == set([1,2,4,5])
+
+ a = set([1,2,3])
+ b = set([3,4,5])
+ a ^= b
+ assert a == set([1,2,4,5])
+
def test_subtype(self):
class subset(set):pass
a = subset()
@@ -131,6 +372,8 @@
assert (set('abc') != set('abcd'))
assert (frozenset('abc') != frozenset('abcd'))
assert (frozenset('abc') != set('abcd'))
+ assert set() != set('abc')
+ assert set('abc') != set('abd')
def test_libpython_equality(self):
for thetype in [frozenset, set]:
@@ -178,6 +421,9 @@
s1 = set('abc')
s1.update('d', 'ef', frozenset('g'))
assert s1 == set('abcdefg')
+ s1 = set()
+ s1.update(set('abcd'))
+ assert s1 == set('abcd')
def test_recursive_repr(self):
class A(object):
@@ -330,6 +576,7 @@
assert not set([1,2,5]).isdisjoint(frozenset([4,5,6]))
assert not set([1,2,5]).isdisjoint([4,5,6])
assert not set([1,2,5]).isdisjoint((4,5,6))
+ assert set([1,2,3]).isdisjoint(set([3.5,4.0]))
def test_intersection(self):
assert set([1,2,3]).intersection(set([2,3,4])) == set([2,3])
@@ -347,6 +594,35 @@
assert s.intersection() == s
assert s.intersection() is not s
+ def test_intersection_swap(self):
+ s1 = s3 = set([1,2,3,4,5])
+ s2 = set([2,3,6,7])
+ s1 &= s2
+ assert s1 == set([2,3])
+ assert s3 == set([2,3])
+
+ def test_intersection_generator(self):
+ def foo():
+ for i in range(5):
+ yield i
+
+ s1 = s2 = set([1,2,3,4,5,6])
+ assert s1.intersection(foo()) == set([1,2,3,4])
+ s1.intersection_update(foo())
+ assert s1 == set([1,2,3,4])
+ assert s2 == set([1,2,3,4])
+
+ def test_intersection_string(self):
+ s = set([1,2,3])
+ o = 'abc'
+ assert s.intersection(o) == set()
+
+ def test_intersection_float(self):
+ a = set([1,2,3])
+ b = set([3.0,4.0,5.0])
+ c = a.intersection(b)
+ assert c == set([3.0])
+
def test_difference(self):
assert set([1,2,3]).difference(set([2,3,4])) == set([1])
assert set([1,2,3]).difference(frozenset([2,3,4])) == set([1])
@@ -361,6 +637,9 @@
s = set([1,2,3])
assert s.difference() == s
assert s.difference() is not s
+ assert set([1,2,3]).difference(set([2,3,4,'5'])) == set([1])
+ assert set([1,2,3,'5']).difference(set([2,3,4])) == set([1,'5'])
+ assert set().difference(set([1,2,3])) == set()
def test_intersection_update(self):
s = set([1,2,3,4,7])
@@ -381,3 +660,250 @@
assert s == set([2,3])
s.difference_update(s)
assert s == set([])
+
+ def test_empty_empty(self):
+ assert set() == set([])
+
+ def test_empty_difference(self):
+ e = set()
+ x = set([1,2,3])
+ assert e.difference(x) == set()
+ assert x.difference(e) == x
+
+ e.difference_update(x)
+ assert e == set()
+ x.difference_update(e)
+ assert x == set([1,2,3])
+
+ assert e.symmetric_difference(x) == x
+ assert x.symmetric_difference(e) == x
+
+ e.symmetric_difference_update(e)
+ assert e == e
+ e.symmetric_difference_update(x)
+ assert e == x
+
+ x.symmetric_difference_update(set())
+ assert x == set([1,2,3])
+
+ def test_fastpath_with_strategies(self):
+ a = set([1,2,3])
+ b = set(["a","b","c"])
+ assert a.difference(b) == a
+ assert b.difference(a) == b
+
+ a = set([1,2,3])
+ b = set(["a","b","c"])
+ assert a.intersection(b) == set()
+ assert b.intersection(a) == set()
+
+ a = set([1,2,3])
+ b = set(["a","b","c"])
+ assert not a.issubset(b)
+ assert not b.issubset(a)
+
+ a = set([1,2,3])
+ b = set(["a","b","c"])
+ assert a.isdisjoint(b)
+ assert b.isdisjoint(a)
+
+ def test_empty_intersect(self):
+ e = set()
+ x = set([1,2,3])
+ assert e.intersection(x) == e
+ assert x.intersection(e) == e
+ assert e & x == e
+ assert x & e == e
+
+ e.intersection_update(x)
+ assert e == set()
+ e &= x
+ assert e == set()
+ x.intersection_update(e)
+ assert x == set()
+
+ def test_empty_issuper(self):
+ e = set()
+ x = set([1,2,3])
+ assert e.issuperset(e) == True
+ assert e.issuperset(x) == False
+ assert x.issuperset(e) == True
+
+ assert e.issuperset(set())
+ assert e.issuperset([])
+
+ def test_empty_issubset(self):
+ e = set()
+ x = set([1,2,3])
+ assert e.issubset(e) == True
+ assert e.issubset(x) == True
+ assert x.issubset(e) == False
+ assert e.issubset([])
+
+ def test_empty_isdisjoint(self):
+ e = set()
+ x = set([1,2,3])
+ assert e.isdisjoint(e) == True
+ assert e.isdisjoint(x) == True
+ assert x.isdisjoint(e) == True
+
+ def test_empty_unhashable(self):
+ s = set()
+ raises(TypeError, s.difference, [[]])
+ raises(TypeError, s.difference_update, [[]])
+ raises(TypeError, s.intersection, [[]])
+ raises(TypeError, s.intersection_update, [[]])
+ raises(TypeError, s.symmetric_difference, [[]])
+ raises(TypeError, s.symmetric_difference_update, [[]])
+ raises(TypeError, s.update, [[]])
+
+ def test_super_with_generator(self):
+ def foo():
+ for i in [1,2,3]:
+ yield i
+ set([1,2,3,4,5]).issuperset(foo())
+
+ def test_isdisjoint_with_generator(self):
+ def foo():
+ for i in [1,2,3]:
+ yield i
+ set([1,2,3,4,5]).isdisjoint(foo())
+
+ def test_fakeint_and_equals(self):
+ s1 = set([1,2,3,4])
+ s2 = set([1,2,self.FakeInt(3), 4])
+ assert s1 == s2
+
+ def test_fakeint_and_discard(self):
+ # test with object strategy
+ s = set([1, 2, 'three', 'four'])
+ s.discard(self.FakeInt(2))
+ assert s == set([1, 'three', 'four'])
+
+ s.remove(self.FakeInt(1))
+ assert s == set(['three', 'four'])
+ raises(KeyError, s.remove, self.FakeInt(16))
+
+ # test with int strategy
+ s = set([1,2,3,4])
+ s.discard(self.FakeInt(4))
+ assert s == set([1,2,3])
+ s.remove(self.FakeInt(3))
+ assert s == set([1,2])
+ raises(KeyError, s.remove, self.FakeInt(16))
+
+ def test_fakeobject_and_has_key(self):
+ s = set([1,2,3,4,5])
+ assert 5 in s
+ assert self.FakeInt(5) in s
+
+ def test_fakeobject_and_pop(self):
+ s = set([1,2,3,self.FakeInt(4),5])
+ assert s.pop()
+ assert s.pop()
+ assert s.pop()
+ assert s.pop()
+ assert s.pop()
+ assert s == set([])
+
+ def test_fakeobject_and_difference(self):
+ s = set([1,2,'3',4])
+ s.difference_update([self.FakeInt(1), self.FakeInt(2)])
+ assert s == set(['3',4])
+
+ s = set([1,2,3,4])
+ s.difference_update([self.FakeInt(1), self.FakeInt(2)])
+ assert s == set([3,4])
+
+ def test_frozenset_behavior(self):
+ s = set([1,2,3,frozenset([4])])
+ raises(TypeError, s.difference_update, [1,2,3,set([4])])
+
+ s = set([1,2,3,frozenset([4])])
+ s.discard(set([4]))
+ assert s == set([1,2,3])
+
+ def test_discard_unhashable(self):
+ s = set([1,2,3,4])
+ raises(TypeError, s.discard, [1])
+
+ def test_discard_evil_compare(self):
+ class Evil(object):
+ def __init__(self, value):
+ self.value = value
+ def __hash__(self):
+ return hash(self.value)
+ def __eq__(self, other):
+ if isinstance(other, frozenset):
+ raise TypeError
+ if other == self.value:
+ return True
+ return False
+ s = set([1,2, Evil(frozenset([1]))])
+ raises(TypeError, s.discard, set([1]))
+
+ def test_create_set_from_set(self):
+ # no sharing
+ x = set([1,2,3])
+ y = set(x)
+ a = x.pop()
+ assert y == set([1,2,3])
+ assert len(x) == 2
+ assert x.union(set([a])) == y
+
+ def test_never_change_frozenset(self):
+ a = frozenset([1,2])
+ b = a.copy()
+ assert a is b
+
+ a = frozenset([1,2])
+ b = a.union(set([3,4]))
+ assert b == set([1,2,3,4])
+ assert a == set([1,2])
+
+ a = frozenset()
+ b = a.union(set([3,4]))
+ assert b == set([3,4])
+ assert a == set()
+
+ a = frozenset([1,2])#multiple
+ b = a.union(set([3,4]),[5,6])
+ assert b == set([1,2,3,4,5,6])
+ assert a == set([1,2])
+
+ a = frozenset([1,2,3])
+ b = a.difference(set([3,4,5]))
+ assert b == set([1,2])
+ assert a == set([1,2,3])
+
+ a = frozenset([1,2,3])#multiple
+ b = a.difference(set([3]), [2])
+ assert b == set([1])
+ assert a == set([1,2,3])
+
+ a = frozenset([1,2,3])
+ b = a.symmetric_difference(set([3,4,5]))
+ assert b == set([1,2,4,5])
+ assert a == set([1,2,3])
+
+ a = frozenset([1,2,3])
+ b = a.intersection(set([3,4,5]))
+ assert b == set([3])
+ assert a == set([1,2,3])
+
+ a = frozenset([1,2,3])#multiple
+ b = a.intersection(set([2,3,4]), [2])
+ assert b == set([2])
+ assert a == set([1,2,3])
+
+ raises(AttributeError, "frozenset().update()")
+ raises(AttributeError, "frozenset().difference_update()")
+ raises(AttributeError, "frozenset().symmetric_difference_update()")
+ raises(AttributeError, "frozenset().intersection_update()")
+
+ def test_intersection_obj(self):
+ class Obj:
+ def __getitem__(self, i):
+ return [5, 3, 4][i]
+ s = set([10,3,2]).intersection(Obj())
+ assert list(s) == [3]
diff --git a/pypy/objspace/std/test/test_setstrategies.py b/pypy/objspace/std/test/test_setstrategies.py
new file mode 100644
--- /dev/null
+++ b/pypy/objspace/std/test/test_setstrategies.py
@@ -0,0 +1,107 @@
+from pypy.objspace.std.setobject import W_SetObject
+from pypy.objspace.std.setobject import IntegerSetStrategy, ObjectSetStrategy, EmptySetStrategy
+from pypy.objspace.std.listobject import W_ListObject
+
+class TestW_SetStrategies:
+
+ def wrapped(self, l):
+ return W_ListObject(self.space, [self.space.wrap(x) for x in l])
+
+ def test_from_list(self):
+ s = W_SetObject(self.space, self.wrapped([1,2,3,4,5]))
+ assert s.strategy is self.space.fromcache(IntegerSetStrategy)
+
+ s = W_SetObject(self.space, self.wrapped([1,"two",3,"four",5]))
+ assert s.strategy is self.space.fromcache(ObjectSetStrategy)
+
+ s = W_SetObject(self.space)
+ assert s.strategy is self.space.fromcache(EmptySetStrategy)
+
+ s = W_SetObject(self.space, self.wrapped([]))
+ assert s.strategy is self.space.fromcache(EmptySetStrategy)
+
+ def test_switch_to_object(self):
+ s = W_SetObject(self.space, self.wrapped([1,2,3,4,5]))
+ s.add(self.space.wrap("six"))
+ assert s.strategy is self.space.fromcache(ObjectSetStrategy)
+
+ s1 = W_SetObject(self.space, self.wrapped([1,2,3,4,5]))
+ s2 = W_SetObject(self.space, self.wrapped(["six", "seven"]))
+ s1.update(s2)
+ assert s1.strategy is self.space.fromcache(ObjectSetStrategy)
+
+ def test_symmetric_difference(self):
+ s1 = W_SetObject(self.space, self.wrapped([1,2,3,4,5]))
+ s2 = W_SetObject(self.space, self.wrapped(["six", "seven"]))
+ s1.symmetric_difference_update(s2)
+ assert s1.strategy is self.space.fromcache(ObjectSetStrategy)
+
+ def test_intersection(self):
+ s1 = W_SetObject(self.space, self.wrapped([1,2,3,4,5]))
+ s2 = W_SetObject(self.space, self.wrapped([4,5, "six", "seven"]))
+ s3 = s1.intersect(s2)
+ skip("for now intersection with ObjectStrategy always results in another ObjectStrategy")
+ assert s3.strategy is self.space.fromcache(IntegerSetStrategy)
+
+ def test_clear(self):
+ s1 = W_SetObject(self.space, self.wrapped([1,2,3,4,5]))
+ s1.clear()
+ assert s1.strategy is self.space.fromcache(EmptySetStrategy)
+
+ def test_remove(self):
+ from pypy.objspace.std.setobject import set_remove__Set_ANY
+ s1 = W_SetObject(self.space, self.wrapped([1]))
+ set_remove__Set_ANY(self.space, s1, self.space.wrap(1))
+ assert s1.strategy is self.space.fromcache(EmptySetStrategy)
+
+ def test_union(self):
+ from pypy.objspace.std.setobject import set_union__Set
+ s1 = W_SetObject(self.space, self.wrapped([1,2,3,4,5]))
+ s2 = W_SetObject(self.space, self.wrapped([4,5,6,7]))
+ s3 = W_SetObject(self.space, self.wrapped([4,'5','6',7]))
+ s4 = set_union__Set(self.space, s1, [s2])
+ s5 = set_union__Set(self.space, s1, [s3])
+ assert s4.strategy is self.space.fromcache(IntegerSetStrategy)
+ assert s5.strategy is self.space.fromcache(ObjectSetStrategy)
+
+ def test_discard(self):
+ class FakeInt(object):
+ def __init__(self, value):
+ self.value = value
+ def __hash__(self):
+ return hash(self.value)
+ def __eq__(self, other):
+ if other == self.value:
+ return True
+ return False
+
+ from pypy.objspace.std.setobject import set_discard__Set_ANY
+
+ s1 = W_SetObject(self.space, self.wrapped([1,2,3,4,5]))
+ set_discard__Set_ANY(self.space, s1, self.space.wrap("five"))
+ skip("currently not supported")
+ assert s1.strategy is self.space.fromcache(IntegerSetStrategy)
+
+ set_discard__Set_ANY(self.space, s1, self.space.wrap(FakeInt(5)))
+ assert s1.strategy is self.space.fromcache(ObjectSetStrategy)
+
+ def test_has_key(self):
+ class FakeInt(object):
+ def __init__(self, value):
+ self.value = value
+ def __hash__(self):
+ return hash(self.value)
+ def __eq__(self, other):
+ if other == self.value:
+ return True
+ return False
+
+ from pypy.objspace.std.setobject import set_discard__Set_ANY
+
+ s1 = W_SetObject(self.space, self.wrapped([1,2,3,4,5]))
+ assert not s1.has_key(self.space.wrap("five"))
+ skip("currently not supported")
+ assert s1.strategy is self.space.fromcache(IntegerSetStrategy)
+
+ assert s1.has_key(self.space.wrap(FakeInt(2)))
+ assert s1.strategy is self.space.fromcache(ObjectSetStrategy)
diff --git a/pypy/objspace/std/test/test_stringobject.py b/pypy/objspace/std/test/test_stringobject.py
--- a/pypy/objspace/std/test/test_stringobject.py
+++ b/pypy/objspace/std/test/test_stringobject.py
@@ -85,6 +85,10 @@
w_slice = space.newslice(w(1), w_None, w(2))
assert self.space.eq_w(space.getitem(w_str, w_slice), w('el'))
+ def test_listview_str(self):
+ w_str = self.space.wrap('abcd')
+ assert self.space.listview_str(w_str) == list("abcd")
+
class AppTestStringObject:
def test_format_wrongchar(self):
diff --git a/pypy/translator/c/gcc/test/test_asmgcroot.py b/pypy/translator/c/gcc/test/test_asmgcroot.py
--- a/pypy/translator/c/gcc/test/test_asmgcroot.py
+++ b/pypy/translator/c/gcc/test/test_asmgcroot.py
@@ -6,10 +6,18 @@
from pypy.annotation.listdef import s_list_of_strings
from pypy import conftest
from pypy.translator.tool.cbuild import ExternalCompilationInfo
+from pypy.translator.platform import platform as compiler
+from pypy.rlib.rarithmetic import is_emulated_long
from pypy.rpython.lltypesystem import lltype, rffi
from pypy.rlib.entrypoint import entrypoint, secondary_entrypoints
from pypy.rpython.lltypesystem.lloperation import llop
+_MSVC = compiler.name == "msvc"
+_MINGW = compiler.name == "mingw32"
+_WIN32 = _MSVC or _MINGW
+_WIN64 = _WIN32 and is_emulated_long
+# XXX get rid of 'is_emulated_long' and have a real config here.
+
class AbstractTestAsmGCRoot:
# the asmgcroot gc transformer doesn't generate gc_reload_possibly_moved
# instructions:
@@ -17,6 +25,8 @@
@classmethod
def make_config(cls):
+ if _MSVC and _WIN64:
+ py.test.skip("all asmgcroot tests disabled for MSVC X64")
from pypy.config.pypyoption import get_pypy_config
config = get_pypy_config(translating=True)
config.translation.gc = cls.gcpolicy
More information about the pypy-commit
mailing list