[pypy-commit] pypy default: merge
cfbolz
noreply at buildbot.pypy.org
Fri Sep 23 13:13:59 CEST 2011
Author: Carl Friedrich Bolz <cfbolz at gmx.de>
Branch:
Changeset: r47509:cba07b6bbd87
Date: 2011-05-24 12:00 +0200
http://bitbucket.org/pypy/pypy/changeset/cba07b6bbd87/
Log: merge
diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py
--- a/pypy/config/pypyoption.py
+++ b/pypy/config/pypyoption.py
@@ -242,6 +242,10 @@
"(the empty string and potentially single-char strings)",
default=False),
+ BoolOption("withsmalltuple",
+ "use small tuples",
+ default=False),
+
BoolOption("withrope", "use ropes as the string implementation",
default=False,
requires=[("objspace.std.withstrslice", False),
diff --git a/pypy/doc/config/objspace.std.withsmalltuple.txt b/pypy/doc/config/objspace.std.withsmalltuple.txt
new file mode 100644
--- /dev/null
+++ b/pypy/doc/config/objspace.std.withsmalltuple.txt
@@ -0,0 +1,1 @@
+Use small tuple objects for sizes from 1 to 3
diff --git a/pypy/module/cpyext/methodobject.py b/pypy/module/cpyext/methodobject.py
--- a/pypy/module/cpyext/methodobject.py
+++ b/pypy/module/cpyext/methodobject.py
@@ -73,29 +73,29 @@
rffi.charp2str(self.ml.c_ml_name) + "() takes no keyword arguments"))
func = rffi.cast(PyCFunction, self.ml.c_ml_meth)
+ length = space.int_w(space.len(w_args))
if flags & METH_KEYWORDS:
func = rffi.cast(PyCFunctionKwArgs, self.ml.c_ml_meth)
return generic_cpy_call(space, func, w_self, w_args, w_kw)
elif flags & METH_NOARGS:
- if len(w_args.wrappeditems) == 0:
+ if length == 0:
return generic_cpy_call(space, func, w_self, None)
raise OperationError(space.w_TypeError, space.wrap(
rffi.charp2str(self.ml.c_ml_name) + "() takes no arguments"))
elif flags & METH_O:
- assert isinstance(w_args, W_TupleObject)
- if len(w_args.wrappeditems) != 1:
+ if length != 1:
raise OperationError(space.w_TypeError,
space.wrap("%s() takes exactly one argument (%d given)" % (
rffi.charp2str(self.ml.c_ml_name),
- len(w_args.wrappeditems))))
- w_arg = w_args.wrappeditems[0]
+ length)))
+ w_arg = space.getitem(w_args, space.wrap(0))
return generic_cpy_call(space, func, w_self, w_arg)
elif flags & METH_VARARGS:
return generic_cpy_call(space, func, w_self, w_args)
else: # METH_OLDARGS, the really old style
- size = len(w_args.wrappeditems)
+ size = length
if size == 1:
- w_arg = w_args.wrappeditems[0]
+ w_arg = space.getitem(w_args, space.wrap(0))
elif size == 0:
w_arg = None
else:
diff --git a/pypy/module/cpyext/test/test_tupleobject.py b/pypy/module/cpyext/test/test_tupleobject.py
--- a/pypy/module/cpyext/test/test_tupleobject.py
+++ b/pypy/module/cpyext/test/test_tupleobject.py
@@ -3,8 +3,10 @@
from pypy.module.cpyext.pyobject import PyObject, PyObjectP, make_ref, from_ref
from pypy.module.cpyext.test.test_api import BaseApiTest
from pypy.rpython.lltypesystem import rffi, lltype
+from pypy.conftest import gettestobjspace
class TestTupleObject(BaseApiTest):
+
def test_tupleobject(self, space, api):
assert not api.PyTuple_Check(space.w_None)
assert api.PyTuple_SetItem(space.w_None, 0, space.w_None) == -1
@@ -20,11 +22,23 @@
ar[0] = rffi.cast(PyObject, make_ref(space, py_tuple))
api._PyTuple_Resize(ar, 2)
py_tuple = from_ref(space, ar[0])
- assert len(py_tuple.wrappeditems) == 2
+ assert space.int_w(space.len(py_tuple)) == 2
api._PyTuple_Resize(ar, 10)
py_tuple = from_ref(space, ar[0])
- assert len(py_tuple.wrappeditems) == 10
+ assert space.int_w(space.len(py_tuple)) == 10
api.Py_DecRef(ar[0])
lltype.free(ar, flavor='raw')
+
+ def test_setitem(self, space, api):
+ atuple = space.newtuple([space.wrap(0), space.wrap("hello")])
+ assert api.PyTuple_Size(atuple) == 2
+ assert space.eq_w(space.getitem(atuple, space.wrap(0)), space.wrap(0))
+ assert space.eq_w(space.getitem(atuple, space.wrap(1)), space.wrap("hello"))
+ w_obj = space.wrap(1)
+ api.Py_IncRef(w_obj)
+ api.PyTuple_SetItem(atuple, 1, w_obj)
+ assert api.PyTuple_Size(atuple) == 2
+ assert space.eq_w(space.getitem(atuple, space.wrap(0)), space.wrap(0))
+ assert space.eq_w(space.getitem(atuple, space.wrap(1)), space.wrap(1))
diff --git a/pypy/module/cpyext/tupleobject.py b/pypy/module/cpyext/tupleobject.py
--- a/pypy/module/cpyext/tupleobject.py
+++ b/pypy/module/cpyext/tupleobject.py
@@ -6,7 +6,7 @@
borrow_from, make_ref, from_ref)
from pypy.module.cpyext.pyerrors import PyErr_BadInternalCall
from pypy.objspace.std.tupleobject import W_TupleObject
-
+from pypy.objspace.std.smalltupleobject import W_SmallTupleObject
PyTuple_Check, PyTuple_CheckExact = build_type_checkers("Tuple")
@@ -19,25 +19,30 @@
if not PyTuple_Check(space, w_t):
# XXX this should also steal a reference, test it!!!
PyErr_BadInternalCall(space)
- assert isinstance(w_t, W_TupleObject)
- w_t.wrappeditems[pos] = w_obj
+ _setitem_tuple(w_t, pos, w_obj)
Py_DecRef(space, w_obj) # SetItem steals a reference!
return 0
+def _setitem_tuple(w_t, pos, w_obj):
+ if isinstance(w_t, W_TupleObject):
+ w_t.wrappeditems[pos] = w_obj
+ elif isinstance(w_t, W_SmallTupleObject):
+ w_t.setitem(pos, w_obj)
+ else:
+ assert False
+
@cpython_api([PyObject, Py_ssize_t], PyObject)
def PyTuple_GetItem(space, w_t, pos):
if not PyTuple_Check(space, w_t):
PyErr_BadInternalCall(space)
- assert isinstance(w_t, W_TupleObject)
- w_obj = w_t.wrappeditems[pos]
+ w_obj = space.getitem(w_t, space.wrap(pos))
return borrow_from(w_t, w_obj)
@cpython_api([PyObject], Py_ssize_t, error=CANNOT_FAIL)
def PyTuple_GET_SIZE(space, w_t):
"""Return the size of the tuple p, which must be non-NULL and point to a tuple;
no error checking is performed. """
- assert isinstance(w_t, W_TupleObject)
- return len(w_t.wrappeditems)
+ return space.int_w(space.len(w_t))
@cpython_api([PyObject], Py_ssize_t, error=-1)
def PyTuple_Size(space, ref):
@@ -63,15 +68,14 @@
py_tuple = from_ref(space, ref[0])
if not PyTuple_Check(space, py_tuple):
PyErr_BadInternalCall(space)
- assert isinstance(py_tuple, W_TupleObject)
py_newtuple = PyTuple_New(space, newsize)
to_cp = newsize
- oldsize = len(py_tuple.wrappeditems)
+ oldsize = space.int_w(space.len(py_tuple))
if oldsize < newsize:
to_cp = oldsize
for i in range(to_cp):
- py_newtuple.wrappeditems[i] = py_tuple.wrappeditems[i]
+ _setitem_tuple(py_newtuple, i, space.getitem(py_tuple, space.wrap(i)))
Py_DecRef(space, ref[0])
ref[0] = make_ref(space, py_newtuple)
return 0
diff --git a/pypy/objspace/std/model.py b/pypy/objspace/std/model.py
--- a/pypy/objspace/std/model.py
+++ b/pypy/objspace/std/model.py
@@ -15,6 +15,7 @@
_registered_implementations.add(implcls)
option_to_typename = {
+ "withsmalltuple" : ["smalltupleobject.W_SmallTupleObject"],
"withsmallint" : ["smallintobject.W_SmallIntObject"],
"withsmalllong" : ["smalllongobject.W_SmallLongObject"],
"withstrslice" : ["strsliceobject.W_StringSliceObject"],
@@ -71,6 +72,7 @@
from pypy.objspace.std import smallintobject
from pypy.objspace.std import smalllongobject
from pypy.objspace.std import tupleobject
+ from pypy.objspace.std import smalltupleobject
from pypy.objspace.std import listobject
from pypy.objspace.std import dictmultiobject
from pypy.objspace.std import stringobject
@@ -253,6 +255,9 @@
(listobject.W_ListObject,
rangeobject.delegate_range2list),
]
+ if config.objspace.std.withsmalltuple:
+ self.typeorder[smalltupleobject.W_SmallTupleObject] += [
+ (tupleobject.W_TupleObject, smalltupleobject.delegate_SmallTuple2Tuple)]
# put W_Root everywhere
self.typeorder[W_Root] = []
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
@@ -295,9 +295,10 @@
return newlong(self, val)
def newtuple(self, list_w):
+ from pypy.objspace.std.tupletype import wraptuple
assert isinstance(list_w, list)
make_sure_not_resized(list_w)
- return W_TupleObject(list_w)
+ return wraptuple(self, list_w)
def newlist(self, list_w):
return W_ListObject(list_w)
diff --git a/pypy/objspace/std/smalltupleobject.py b/pypy/objspace/std/smalltupleobject.py
new file mode 100644
--- /dev/null
+++ b/pypy/objspace/std/smalltupleobject.py
@@ -0,0 +1,157 @@
+from pypy.interpreter.error import OperationError
+from pypy.objspace.std.model import registerimplementation, W_Object
+from pypy.objspace.std.register_all import register_all
+from pypy.objspace.std.inttype import wrapint
+from pypy.objspace.std.multimethod import FailedToImplement
+from pypy.rlib.rarithmetic import intmask
+from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice
+from pypy.objspace.std import slicetype
+from pypy.interpreter import gateway
+from pypy.rlib.debug import make_sure_not_resized
+from pypy.rlib.unroll import unrolling_iterable
+from pypy.objspace.std.tupleobject import W_TupleObject
+
+class W_SmallTupleObject(W_Object):
+ from pypy.objspace.std.tupletype import tuple_typedef as typedef
+
+ def tolist(self):
+ raise NotImplementedError
+
+ def length(self):
+ raise NotImplementedError
+
+ def getitem(self, index):
+ raise NotImplementedError
+
+ def hash(self, space):
+ raise NotImplementedError
+
+ def eq(self, space, w_other):
+ raise NotImplementedError
+
+ def setitem(self, index, w_item):
+ raise NotImplementedError
+
+ def unwrap(w_tuple, space):
+ items = [space.unwrap(w_item) for w_item in w_tuple.tolist()] # XXX generic mixed types unwrap
+ return tuple(items)
+
+def make_specialized_class(n):
+ iter_n = unrolling_iterable(range(n))
+ class cls(W_SmallTupleObject):
+
+ def __init__(self, values):
+ assert len(values) == n
+ for i in iter_n:
+ setattr(self, 'w_value%s' % i, values[i])
+
+ def tolist(self):
+ l = [None] * n
+ for i in iter_n:
+ l[i] = getattr(self, 'w_value%s' % i)
+ return l
+
+ def length(self):
+ return n
+
+ def getitem(self, index):
+ for i in iter_n:
+ if index == i:
+ return getattr(self,'w_value%s' % i)
+ raise IndexError
+
+ def setitem(self, index, w_item):
+ for i in iter_n:
+ if index == i:
+ setattr(self, 'w_value%s' % i, w_item)
+ return
+ raise IndexError
+
+ def eq(self, space, w_other):
+ if self.length() != w_other.length():
+ return space.w_False
+ for i in iter_n:
+ item1 = self.getitem(i)
+ item2 = w_other.getitem(i)
+ if not space.eq_w(item1, item2):
+ return space.w_False
+ return space.w_True
+
+ def hash(self, space):
+ mult = 1000003
+ x = 0x345678
+ z = self.length()
+ for i in iter_n:
+ w_item = self.getitem(i)
+ y = space.int_w(space.hash(w_item))
+ x = (x ^ y) * mult
+ z -= 1
+ mult += 82520 + z + z
+ x += 97531
+ return space.wrap(intmask(x))
+
+ cls.__name__ = "W_SmallTupleObject%s" % n
+ return cls
+
+W_SmallTupleObject2 = make_specialized_class(2)
+W_SmallTupleObject3 = make_specialized_class(3)
+W_SmallTupleObject4 = make_specialized_class(4)
+W_SmallTupleObject5 = make_specialized_class(5)
+W_SmallTupleObject6 = make_specialized_class(6)
+W_SmallTupleObject7 = make_specialized_class(7)
+W_SmallTupleObject8 = make_specialized_class(8)
+
+registerimplementation(W_SmallTupleObject)
+
+def delegate_SmallTuple2Tuple(space, w_small):
+ return W_TupleObject(w_small.tolist())
+
+def len__SmallTuple(space, w_tuple):
+ return space.wrap(w_tuple.length())
+
+def getitem__SmallTuple_ANY(space, w_tuple, w_index):
+ index = space.getindex_w(w_index, space.w_IndexError, "tuple index")
+ if index < 0:
+ index += w_tuple.length()
+ try:
+ return w_tuple.getitem(index)
+ except IndexError:
+ raise OperationError(space.w_IndexError,
+ space.wrap("tuple index out of range"))
+
+def getitem__SmallTuple_Slice(space, w_tuple, w_slice):
+ length = w_tuple.length()
+ start, stop, step, slicelength = w_slice.indices4(space, length)
+ assert slicelength >= 0
+ subitems = [None] * slicelength
+ for i in range(slicelength):
+ subitems[i] = w_tuple.getitem(start)
+ start += step
+ return space.newtuple(subitems)
+
+def mul_smalltuple_times(space, w_tuple, w_times):
+ try:
+ times = space.getindex_w(w_times, space.w_OverflowError)
+ except OperationError, e:
+ if e.match(space, space.w_TypeError):
+ raise FailedToImplement
+ raise
+ if times == 1 and space.type(w_tuple) == space.w_tuple:
+ return w_tuple
+ items = w_tuple.tolist()
+ return space.newtuple(items * times)
+
+def mul__SmallTuple_ANY(space, w_tuple, w_times):
+ return mul_smalltuple_times(space, w_tuple, w_times)
+
+def mul__ANY_SmallTuple(space, w_times, w_tuple):
+ return mul_smalltuple_times(space, w_tuple, w_times)
+
+def eq__SmallTuple_SmallTuple(space, w_tuple1, w_tuple2):
+ return w_tuple1.eq(space, w_tuple2)
+
+def hash__SmallTuple(space, w_tuple):
+ return w_tuple.hash(space)
+
+from pypy.objspace.std import tupletype
+register_all(vars(), tupletype)
diff --git a/pypy/objspace/std/test/test_smalltupleobject.py b/pypy/objspace/std/test/test_smalltupleobject.py
new file mode 100644
--- /dev/null
+++ b/pypy/objspace/std/test/test_smalltupleobject.py
@@ -0,0 +1,86 @@
+from pypy.objspace.std.tupleobject import W_TupleObject
+from pypy.objspace.std.smalltupleobject import W_SmallTupleObject
+from pypy.interpreter.error import OperationError
+from pypy.objspace.std.test.test_tupleobject import AppTestW_TupleObject
+from pypy.conftest import gettestobjspace
+
+class AppTestW_SmallTupleObject(AppTestW_TupleObject):
+
+ def setup_class(cls):
+ cls.space = gettestobjspace(**{"objspace.std.withsmalltuple": True})
+ cls.w_issmall = cls.space.appexec([], """():
+ import __pypy__
+ def issmall(obj):
+ assert "SmallTuple" in __pypy__.internal_repr(obj)
+ return issmall
+ """)
+
+ def test_smalltuple(self):
+ self.issmall((1,2))
+ self.issmall((1,2,3))
+
+ def test_slicing_to_small(self):
+ self.issmall((1, 2, 3)[0:2]) # SmallTuple2
+ self.issmall((1, 2, 3)[0:2:1])
+
+ self.issmall((1, 2, 3, 4)[0:3]) # SmallTuple3
+ self.issmall((1, 2, 3, 4)[0:3:1])
+
+ def test_adding_to_small(self):
+ self.issmall((1,)+(2,)) # SmallTuple2
+ self.issmall((1,1)+(2,)) # SmallTuple3
+ self.issmall((1,)+(2,3))
+
+ def test_multiply_to_small(self):
+ self.issmall((1,)*2)
+ self.issmall((1,)*3)
+
+ def test_slicing_from_small(self):
+ assert (1,2)[0:1:1] == (1,)
+ assert (1,2,3)[0:2:1] == (1,2)
+
+ def test_eq(self):
+ a = (1,2,3)
+ b = (1,2,3)
+ assert a == b
+
+ c = (1,3,2)
+ assert a != c
+
+ def test_hash(self):
+ a = (1,2,3)
+ b = (1,2,3)
+ assert hash(a) == hash(b)
+
+ c = (1,3,2)
+ assert hash(a) != hash(c)
+
+class TestW_SmallTupleObject():
+
+ def setup_class(cls):
+ cls.space = gettestobjspace(**{"objspace.std.withsmalltuple": True})
+
+ def test_issmalltupleobject(self):
+ w_tuple = self.space.newtuple([self.space.wrap(1), self.space.wrap(2)])
+ assert isinstance(w_tuple, W_SmallTupleObject)
+
+ def test_hash_agains_normal_tuple(self):
+ normalspace = gettestobjspace(**{"objspace.std.withsmalltuple": False})
+ w_tuple = normalspace.newtuple([self.space.wrap(1), self.space.wrap(2)])
+
+ smallspace = gettestobjspace(**{"objspace.std.withsmalltuple": True})
+ w_smalltuple = smallspace.newtuple([self.space.wrap(1), self.space.wrap(2)])
+
+ assert isinstance(w_smalltuple, W_SmallTupleObject)
+ assert isinstance(w_tuple, W_TupleObject)
+ assert not normalspace.is_true(normalspace.eq(w_tuple, w_smalltuple))
+ assert smallspace.is_true(smallspace.eq(w_tuple, w_smalltuple))
+ assert smallspace.is_true(smallspace.eq(normalspace.hash(w_tuple), smallspace.hash(w_smalltuple)))
+
+ def test_setitem(self):
+ w_smalltuple = self.space.newtuple([self.space.wrap(1), self.space.wrap(2)])
+ w_smalltuple.setitem(0, self.space.wrap(5))
+ list_w = w_smalltuple.tolist()
+ assert len(list_w) == 2
+ assert self.space.eq_w(list_w[0], self.space.wrap(5))
+ assert self.space.eq_w(list_w[1], self.space.wrap(2))
diff --git a/pypy/objspace/std/tupleobject.py b/pypy/objspace/std/tupleobject.py
--- a/pypy/objspace/std/tupleobject.py
+++ b/pypy/objspace/std/tupleobject.py
@@ -56,12 +56,12 @@
for i in range(slicelength):
subitems[i] = items[start]
start += step
- return W_TupleObject(subitems)
+ return space.newtuple(subitems)
def getslice__Tuple_ANY_ANY(space, w_tuple, w_start, w_stop):
length = len(w_tuple.wrappeditems)
start, stop = normalize_simple_slice(space, length, w_start, w_stop)
- return W_TupleObject(w_tuple.wrappeditems[start:stop])
+ return space.newtuple(w_tuple.wrappeditems[start:stop])
def contains__Tuple_ANY(space, w_tuple, w_obj):
for w_item in w_tuple.wrappeditems:
@@ -76,7 +76,7 @@
def add__Tuple_Tuple(space, w_tuple1, w_tuple2):
items1 = w_tuple1.wrappeditems
items2 = w_tuple2.wrappeditems
- return W_TupleObject(items1 + items2)
+ return space.newtuple(items1 + items2)
def mul_tuple_times(space, w_tuple, w_times):
try:
@@ -88,7 +88,7 @@
if times == 1 and space.type(w_tuple) == space.w_tuple:
return w_tuple
items = w_tuple.wrappeditems
- return W_TupleObject(items * times)
+ return space.newtuple(items * times)
def mul__Tuple_ANY(space, w_tuple, w_times):
return mul_tuple_times(space, w_tuple, w_times)
@@ -162,7 +162,7 @@
return intmask(x)
def getnewargs__Tuple(space, w_tuple):
- return space.newtuple([W_TupleObject(w_tuple.wrappeditems)])
+ return space.newtuple([space.newtuple(w_tuple.wrappeditems)])
def tuple_count__Tuple_ANY(space, w_tuple, w_obj):
count = 0
diff --git a/pypy/objspace/std/tupletype.py b/pypy/objspace/std/tupletype.py
--- a/pypy/objspace/std/tupletype.py
+++ b/pypy/objspace/std/tupletype.py
@@ -3,6 +3,31 @@
from pypy.objspace.std.register_all import register_all
from pypy.objspace.std.stdtypedef import StdTypeDef, SMM
+def wraptuple(space, list_w):
+ from pypy.objspace.std.tupleobject import W_TupleObject
+ from pypy.objspace.std.smalltupleobject import W_SmallTupleObject2
+ from pypy.objspace.std.smalltupleobject import W_SmallTupleObject3
+ from pypy.objspace.std.smalltupleobject import W_SmallTupleObject4
+ from pypy.objspace.std.smalltupleobject import W_SmallTupleObject5
+ from pypy.objspace.std.smalltupleobject import W_SmallTupleObject6
+ from pypy.objspace.std.smalltupleobject import W_SmallTupleObject7
+ from pypy.objspace.std.smalltupleobject import W_SmallTupleObject8
+ if space.config.objspace.std.withsmalltuple:
+ if len(list_w) == 2:
+ return W_SmallTupleObject2(list_w)
+ if len(list_w) == 3:
+ return W_SmallTupleObject3(list_w)
+ if len(list_w) == 4:
+ return W_SmallTupleObject4(list_w)
+ if len(list_w) == 5:
+ return W_SmallTupleObject5(list_w)
+ if len(list_w) == 6:
+ return W_SmallTupleObject6(list_w)
+ if len(list_w) == 7:
+ return W_SmallTupleObject7(list_w)
+ if len(list_w) == 8:
+ return W_SmallTupleObject8(list_w)
+ return W_TupleObject(list_w)
tuple_count = SMM("count", 2,
doc="count(obj) -> number of times obj appears in the tuple")
More information about the pypy-commit
mailing list