[pypy-commit] pypy remove-iter-smm: hg merge default

Manuel Jacob noreply at buildbot.pypy.org
Wed May 22 22:16:02 CEST 2013


Author: Manuel Jacob
Branch: remove-iter-smm
Changeset: r64478:b1e0c5ec2b32
Date: 2013-05-22 21:56 +0200
http://bitbucket.org/pypy/pypy/changeset/b1e0c5ec2b32/

Log:	hg merge default

diff --git a/pypy/module/_cffi_backend/__init__.py b/pypy/module/_cffi_backend/__init__.py
--- a/pypy/module/_cffi_backend/__init__.py
+++ b/pypy/module/_cffi_backend/__init__.py
@@ -7,7 +7,7 @@
     appleveldefs = {
         }
     interpleveldefs = {
-        '__version__': 'space.wrap("0.6")',
+        '__version__': 'space.wrap("0.7")',
 
         'load_library': 'libraryobj.load_library',
 
@@ -30,6 +30,8 @@
         'typeoffsetof': 'func.typeoffsetof',
         'rawaddressof': 'func.rawaddressof',
         'getcname': 'func.getcname',
+        'newp_handle': 'handle.newp_handle',
+        'from_handle': 'handle.from_handle',
         '_get_types': 'func._get_types',
 
         'string': 'func.string',
diff --git a/pypy/module/_cffi_backend/cdataobj.py b/pypy/module/_cffi_backend/cdataobj.py
--- a/pypy/module/_cffi_backend/cdataobj.py
+++ b/pypy/module/_cffi_backend/cdataobj.py
@@ -394,6 +394,19 @@
         return self.length
 
 
+class W_CDataHandle(W_CData):
+    _attrs_ = ['w_keepalive']
+    _immutable_fields_ = ['w_keepalive']
+
+    def __init__(self, space, cdata, ctype, w_keepalive):
+        W_CData.__init__(self, space, cdata, ctype)
+        self.w_keepalive = w_keepalive
+
+    def _repr_extra(self):
+        w_repr = self.space.repr(self.w_keepalive)
+        return "handle to %s" % (self.space.str_w(w_repr),)
+
+
 W_CData.typedef = TypeDef(
     'CData',
     __module__ = '_cffi_backend',
diff --git a/pypy/module/_cffi_backend/ctypeptr.py b/pypy/module/_cffi_backend/ctypeptr.py
--- a/pypy/module/_cffi_backend/ctypeptr.py
+++ b/pypy/module/_cffi_backend/ctypeptr.py
@@ -172,8 +172,8 @@
 
 
 class W_CTypePointer(W_CTypePtrBase):
-    _attrs_ = ['is_file', 'cache_array_type']
-    _immutable_fields_ = ['is_file', 'cache_array_type?']
+    _attrs_ = ['is_file', 'cache_array_type', 'is_void_ptr']
+    _immutable_fields_ = ['is_file', 'cache_array_type?', 'is_void_ptr']
     kind = "pointer"
     cache_array_type = None
 
@@ -186,6 +186,7 @@
             extra = " *"
         self.is_file = (ctitem.name == "struct _IO_FILE" or
                         ctitem.name == "struct $FILE")
+        self.is_void_ptr = isinstance(ctitem, ctypevoid.W_CTypeVoid)
         W_CTypePtrBase.__init__(self, space, size, extra, 2, ctitem)
 
     def newp(self, w_init):
diff --git a/pypy/module/_cffi_backend/handle.py b/pypy/module/_cffi_backend/handle.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_cffi_backend/handle.py
@@ -0,0 +1,93 @@
+import weakref
+from pypy.interpreter.error import OperationError, operationerrfmt
+from pypy.interpreter.gateway import unwrap_spec
+from pypy.module._cffi_backend import ctypeobj, ctypeptr, cdataobj
+from pypy.module._weakref.interp__weakref import dead_ref
+from rpython.rtyper.lltypesystem import lltype, rffi
+
+
+def reduced_value(s):
+    while True:
+        divide = s & 1
+        s >>= 1
+        if not divide:
+            return s
+
+# ____________________________________________________________
+
+
+class CffiHandles:
+    def __init__(self, space):
+        self.handles = []
+        self.look_distance = 0
+
+    def reserve_next_handle_index(self):
+        # The reservation ordering done here is tweaked for pypy's
+        # memory allocator.  We look from index 'look_distance'.
+        # Look_distance increases from 0.  But we also look at
+        # "look_distance/2" or "/4" or "/8", etc.  If we find that one
+        # of these secondary locations is free, we assume it's because
+        # there was recently a minor collection; so we reset
+        # look_distance to 0 and start again from the lowest locations.
+        length = len(self.handles)
+        for d in range(self.look_distance, length):
+            if self.handles[d]() is None:
+                self.look_distance = d + 1
+                return d
+            s = reduced_value(d)
+            if self.handles[s]() is None:
+                break
+        # restart from the beginning
+        for d in range(0, length):
+            if self.handles[d]() is None:
+                self.look_distance = d + 1
+                return d
+        # full! extend, but don't use '!=' here
+        self.handles = self.handles + [dead_ref] * (length // 3 + 5)
+        self.look_distance = length + 1
+        return length
+
+    def store_handle(self, index, content):
+        self.handles[index] = weakref.ref(content)
+
+    def fetch_handle(self, index):
+        if 0 <= index < len(self.handles):
+            return self.handles[index]()
+        return None
+
+def get(space):
+    return space.fromcache(CffiHandles)
+
+# ____________________________________________________________
+
+ at unwrap_spec(w_ctype=ctypeobj.W_CType)
+def newp_handle(space, w_ctype, w_x):
+    if (not isinstance(w_ctype, ctypeptr.W_CTypePointer) or
+        not w_ctype.is_void_ptr):
+        raise operationerrfmt(space.w_TypeError,
+                              "needs 'void *', got '%s'", w_ctype.name)
+    index = get(space).reserve_next_handle_index()
+    _cdata = rffi.cast(rffi.CCHARP, index + 1)
+    new_cdataobj = cdataobj.W_CDataHandle(space, _cdata, w_ctype, w_x)
+    get(space).store_handle(index, new_cdataobj)
+    return new_cdataobj
+
+ at unwrap_spec(w_cdata=cdataobj.W_CData)
+def from_handle(space, w_cdata):
+    ctype = w_cdata.ctype
+    if (not isinstance(ctype, ctypeptr.W_CTypePtrOrArray) or
+        not ctype.can_cast_anything):
+        raise operationerrfmt(space.w_TypeError,
+                              "expected a 'cdata' object with a 'void *' out "
+                              "of new_handle(), got '%s'", ctype.name)
+    index = rffi.cast(lltype.Signed, w_cdata._cdata)
+    original_cdataobj = get(space).fetch_handle(index - 1)
+    #
+    if isinstance(original_cdataobj, cdataobj.W_CDataHandle):
+        return original_cdataobj.w_keepalive
+    else:
+        if index == 0:
+            msg = "cannot use from_handle() on NULL pointer"
+        else:
+            msg = "'void *' value does not correspond to any object"
+        raise OperationError(space.w_RuntimeError, space.wrap(msg))
diff --git a/pypy/module/_cffi_backend/test/_backend_test_c.py b/pypy/module/_cffi_backend/test/_backend_test_c.py
--- a/pypy/module/_cffi_backend/test/_backend_test_c.py
+++ b/pypy/module/_cffi_backend/test/_backend_test_c.py
@@ -2732,6 +2732,32 @@
     assert x != cast(BIntP, 12344)
     assert hash(x) == hash(cast(BIntP, 12345))
 
+def test_new_handle():
+    import _weakref
+    BVoidP = new_pointer_type(new_void_type())
+    BCharP = new_pointer_type(new_primitive_type("char"))
+    class mylist(list):
+        pass
+    o = mylist([2, 3, 4])
+    x = newp_handle(BVoidP, o)
+    assert repr(x) == "<cdata 'void *' handle to [2, 3, 4]>"
+    assert x
+    assert from_handle(x) is o
+    assert from_handle(cast(BCharP, x)) is o
+    wr = _weakref.ref(o)
+    del o
+    import gc; gc.collect()
+    assert wr() is not None
+    assert from_handle(x) == list((2, 3, 4))
+    assert from_handle(cast(BCharP, x)) == list((2, 3, 4))
+    del x
+    for i in range(3):
+        if wr() is not None:
+            import gc; gc.collect()
+    assert wr() is None
+    py.test.raises(RuntimeError, from_handle, cast(BCharP, 0))
+
+
 def test_version():
     # this test is here mostly for PyPy
-    assert __version__ == "0.6"
+    assert __version__ == "0.7"
diff --git a/pypy/module/_cffi_backend/test/test_handle.py b/pypy/module/_cffi_backend/test/test_handle.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_cffi_backend/test/test_handle.py
@@ -0,0 +1,59 @@
+import random
+from pypy.module._cffi_backend.handle import CffiHandles, reduced_value
+
+
+def test_reduced_value():
+    assert reduced_value(0) == 0
+    assert reduced_value(1) == 0
+    assert reduced_value(2) == 1
+    assert reduced_value(3) == 0
+    assert reduced_value(4) == 2
+    assert reduced_value(5) == 1
+    assert reduced_value(6) == 3
+    assert reduced_value(7) == 0
+    assert reduced_value(8) == 4
+    assert reduced_value(9) == 2
+    assert reduced_value(10) == 5
+    assert reduced_value(11) == 1
+
+
+class PseudoWeakRef(object):
+    _content = 42
+
+    def __call__(self):
+        return self._content
+
+
+def test_cffi_handles_1():
+    ch = CffiHandles(None)
+    expected_content = {}
+    for i in range(10000):
+        index = ch.reserve_next_handle_index()
+        assert 0 <= index < len(ch.handles)
+        assert ch.handles[index]() is None
+        pwr = PseudoWeakRef()
+        expected_content[index] = pwr
+        ch.handles[index] = pwr
+    assert len(ch.handles) < 13500
+    for index, pwr in expected_content.items():
+        assert ch.handles[index] is pwr
+
+def test_cffi_handles_2():
+    ch = CffiHandles(None)
+    expected_content = {}
+    for i in range(10000):
+        index = ch.reserve_next_handle_index()
+        assert 0 <= index < len(ch.handles)
+        assert ch.handles[index]() is None
+        pwr = PseudoWeakRef()
+        expected_content[index] = pwr
+        ch.handles[index] = pwr
+        #
+        if len(expected_content) > 20:
+            r = random.choice(list(expected_content))
+            pwr = expected_content.pop(r)
+            pwr._content = None
+        #
+    assert len(ch.handles) < 100
+    for index, pwr in expected_content.items():
+        assert ch.handles[index] is pwr
diff --git a/pypy/module/micronumpy/arrayimpl/concrete.py b/pypy/module/micronumpy/arrayimpl/concrete.py
--- a/pypy/module/micronumpy/arrayimpl/concrete.py
+++ b/pypy/module/micronumpy/arrayimpl/concrete.py
@@ -11,7 +11,6 @@
 from rpython.rtyper.lltypesystem import rffi, lltype
 from rpython.rlib.rawstorage import free_raw_storage, raw_storage_getitem,\
      raw_storage_setitem, RAW_STORAGE
-from pypy.module.micronumpy.arrayimpl.sort import argsort_array
 from rpython.rlib.debug import make_sure_not_resized
 
 
@@ -70,6 +69,7 @@
             new_backstrides = [0] * ndims
             for nd in range(ndims):
                 new_backstrides[nd] = (new_shape[nd] - 1) * new_strides[nd]
+            assert isinstance(orig_array, W_NDimArray) or orig_array is None
             return SliceArray(self.start, new_strides, new_backstrides,
                               new_shape, self, orig_array)
         else:
@@ -324,6 +324,7 @@
                           orig_array)
 
     def argsort(self, space, w_axis):
+        from pypy.module.micronumpy.arrayimpl.sort import argsort_array
         return argsort_array(self, space, w_axis)
 
     def base(self):
@@ -356,13 +357,13 @@
         self.strides = strides
         self.backstrides = backstrides
         self.shape = shape
+        if dtype is None:
+            dtype = parent.dtype
         if isinstance(parent, SliceArray):
             parent = parent.parent # one level only
         self.parent = parent
         self.storage = parent.storage
         self.order = parent.order
-        if dtype is None:
-            dtype = parent.dtype
         self.dtype = dtype
         self.size = support.product(shape) * self.dtype.itemtype.get_element_size()
         self.start = start
diff --git a/pypy/module/micronumpy/arrayimpl/scalar.py b/pypy/module/micronumpy/arrayimpl/scalar.py
--- a/pypy/module/micronumpy/arrayimpl/scalar.py
+++ b/pypy/module/micronumpy/arrayimpl/scalar.py
@@ -2,6 +2,7 @@
 from pypy.module.micronumpy.arrayimpl import base
 from pypy.module.micronumpy.base import W_NDimArray, convert_to_array
 from pypy.module.micronumpy import support
+from pypy.module.micronumpy.interp_boxes import W_GenericBox
 from pypy.interpreter.error import OperationError
 
 class ScalarIterator(base.BaseArrayIterator):
@@ -48,6 +49,7 @@
         return self.value
 
     def set_scalar_value(self, w_val):
+        assert isinstance(w_val, W_GenericBox)
         self.value = w_val.convert_to(self.dtype)
 
     def copy(self, space):
@@ -73,7 +75,7 @@
         dtype = self.dtype.float_type or self.dtype
         if len(w_arr.get_shape()) > 0:
             raise OperationError(space.w_ValueError, space.wrap(
-                "could not broadcast input array from shape " + 
+                "could not broadcast input array from shape " +
                 "(%s) into shape ()" % (
                     ','.join([str(x) for x in w_arr.get_shape()],))))
         if self.dtype.is_complex_type():
@@ -102,7 +104,7 @@
         dtype = self.dtype.float_type
         if len(w_arr.get_shape()) > 0:
             raise OperationError(space.w_ValueError, space.wrap(
-                "could not broadcast input array from shape " + 
+                "could not broadcast input array from shape " +
                 "(%s) into shape ()" % (
                     ','.join([str(x) for x in w_arr.get_shape()],))))
         self.value = self.dtype.itemtype.composite(
diff --git a/pypy/module/micronumpy/base.py b/pypy/module/micronumpy/base.py
--- a/pypy/module/micronumpy/base.py
+++ b/pypy/module/micronumpy/base.py
@@ -27,10 +27,10 @@
         from pypy.module.micronumpy.arrayimpl import concrete, scalar
 
         if not shape:
-            impl = scalar.Scalar(dtype)
+            impl = scalar.Scalar(dtype.base)
         else:
-            strides, backstrides = calc_strides(shape, dtype, order)
-            impl = concrete.ConcreteArray(shape, dtype, order, strides,
+            strides, backstrides = calc_strides(shape, dtype.base, order)
+            impl = concrete.ConcreteArray(shape, dtype.base, order, strides,
                                       backstrides)
         return W_NDimArray(impl)
 
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
@@ -268,14 +268,30 @@
 
 
 class W_VoidBox(W_FlexibleBox):
-    @unwrap_spec(item=str)
-    def descr_getitem(self, space, item):
+    def descr_getitem(self, space, w_item):
+        from pypy.module.micronumpy.types import VoidType
+        if space.isinstance_w(w_item, space.w_str):
+            item = space.str_w(w_item)
+        elif space.isinstance_w(w_item, space.w_int):
+            #Called by iterator protocol
+            indx = space.int_w(w_item)
+            try:
+                item = self.dtype.fieldnames[indx]
+            except IndexError:
+                raise OperationError(space.w_IndexError,
+                     space.wrap("Iterated over too many fields %d" % indx))
+        else:
+            raise OperationError(space.w_IndexError, space.wrap(
+                    "Can only access fields of record with int or str"))
         try:
             ofs, dtype = self.dtype.fields[item]
         except KeyError:
             raise OperationError(space.w_IndexError,
                                  space.wrap("Field %s does not exist" % item))
-        read_val = dtype.itemtype.read(self.arr, self.ofs, ofs, dtype)
+        if isinstance(dtype.itemtype, VoidType):
+            read_val = dtype.itemtype.readarray(self.arr, self.ofs, ofs, dtype)
+        else:
+            read_val = dtype.itemtype.read(self.arr, self.ofs, ofs, dtype)
         if isinstance (read_val, W_StringBox):
             # StringType returns a str
             return space.wrap(dtype.itemtype.to_str(read_val))
@@ -373,7 +389,7 @@
     W_LongDoubleBox = W_Float64Box
     W_CLongDoubleBox = W_Complex64Box
 
-    
+
 W_GenericBox.typedef = TypeDef("generic",
     __module__ = "numpypy",
 
diff --git a/pypy/module/micronumpy/interp_dtype.py b/pypy/module/micronumpy/interp_dtype.py
--- a/pypy/module/micronumpy/interp_dtype.py
+++ b/pypy/module/micronumpy/interp_dtype.py
@@ -46,11 +46,11 @@
 
 
 class W_Dtype(W_Root):
-    _immutable_fields_ = ["itemtype", "num", "kind"]
+    _immutable_fields_ = ["itemtype", "num", "kind", "shape"]
 
     def __init__(self, itemtype, num, kind, name, char, w_box_type,
                  alternate_constructors=[], aliases=[],
-                 fields=None, fieldnames=None, native=True):
+                 fields=None, fieldnames=None, native=True, shape=[], subdtype=None):
         self.itemtype = itemtype
         self.num = num
         self.kind = kind
@@ -63,6 +63,12 @@
         self.fieldnames = fieldnames
         self.native = native
         self.float_type = None
+        self.shape = list(shape)
+        self.subdtype = subdtype
+        if not subdtype:
+            self.base = self
+        else:
+            self.base = subdtype.base
 
     @specialize.argtype(1)
     def box(self, value):
@@ -78,7 +84,8 @@
         return self.itemtype.coerce(space, self, w_item)
 
     def getitem(self, arr, i):
-        return self.itemtype.read(arr, i, 0)
+        item = self.itemtype.read(arr, i, 0)
+        return item
 
     def getitem_bool(self, arr, i):
         return self.itemtype.read_bool(arr, i, 0)
@@ -111,8 +118,15 @@
     def descr_get_alignment(self, space):
         return space.wrap(self.itemtype.alignment)
 
+    def descr_get_base(self, space):
+        return space.wrap(self.base)
+
+    def descr_get_subdtype(self, space):
+        return space.newtuple([space.wrap(self.subdtype), self.descr_get_shape(space)])
+
     def descr_get_shape(self, space):
-        return space.newtuple([])
+        w_shape = [space.wrap(dim) for dim in self.shape]
+        return space.newtuple(w_shape)
 
     def eq(self, space, w_other):
         w_other = space.call_function(space.gettypefor(W_Dtype), w_other)
@@ -279,15 +293,22 @@
     ofs_and_items = []
     fieldnames = []
     for w_elem in lst_w:
-        w_fldname, w_flddesc = space.fixedview(w_elem, 2)
-        subdtype = descr__new__(space, space.gettypefor(W_Dtype), w_flddesc)
+        size = 1
+        w_shape = space.newtuple([])
+        if space.len_w(w_elem) == 3:
+            w_fldname, w_flddesc, w_shape = space.fixedview(w_elem)
+            if not base.issequence_w(space, w_shape):
+                w_shape = space.newtuple([w_shape,])
+        else:
+            w_fldname, w_flddesc = space.fixedview(w_elem)
+        subdtype = descr__new__(space, space.gettypefor(W_Dtype), w_flddesc, w_shape=w_shape)
         fldname = space.str_w(w_fldname)
         if fldname in fields:
             raise OperationError(space.w_ValueError, space.wrap("two fields with the same name"))
         assert isinstance(subdtype, W_Dtype)
         fields[fldname] = (offset, subdtype)
         ofs_and_items.append((offset, subdtype.itemtype))
-        offset += subdtype.itemtype.get_element_size()
+        offset += subdtype.itemtype.get_element_size() * size
         fieldnames.append(fldname)
     itemtype = types.RecordType(ofs_and_items, offset)
     return W_Dtype(itemtype, 20, VOIDLTR, "void" + str(8 * itemtype.get_element_size()),
@@ -333,10 +354,24 @@
         raise OperationError(space.w_NotImplementedError, space.wrap(
             "dtype from spec"))
 
-def descr__new__(space, w_subtype, w_dtype, w_align=None, w_copy=None):
+def descr__new__(space, w_subtype, w_dtype, w_align=None, w_copy=None, w_shape=None):
     # w_align and w_copy are necessary for pickling
     cache = get_dtype_cache(space)
 
+    if w_shape is not None and (space.isinstance_w(w_shape, space.w_int) or space.len_w(w_shape) > 0):
+        subdtype = descr__new__(space, w_subtype, w_dtype, w_align, w_copy)
+        assert isinstance(subdtype, W_Dtype)
+        size = 1
+        if space.isinstance_w(w_shape, space.w_int):
+            w_shape = space.newtuple([w_shape])
+        shape = []
+        for w_dim in space.fixedview(w_shape):
+            dim = space.int_w(w_dim)
+            shape.append(dim)
+            size *= dim
+        return W_Dtype(types.VoidType(subdtype.itemtype.get_element_size() * size), 20, VOIDLTR, "void" + str(8 * subdtype.itemtype.get_element_size() * size),
+                    "V", space.gettypefor(interp_boxes.W_VoidBox), shape=shape, subdtype=subdtype)
+
     if space.is_none(w_dtype):
         return cache.w_float64dtype
     elif space.isinstance_w(w_dtype, w_subtype):
@@ -355,6 +390,8 @@
                        "data type %s not understood" % name))
     elif space.isinstance_w(w_dtype, space.w_list):
         return dtype_from_list(space, w_dtype)
+    elif space.isinstance_w(w_dtype, space.w_tuple):
+        return descr__new__(space, w_subtype, space.getitem(w_dtype, space.wrap(0)), w_align, w_copy, w_shape=space.getitem(w_dtype, space.wrap(1)))
     elif space.isinstance_w(w_dtype, space.w_dict):
         return dtype_from_dict(space, w_dtype)
     for dtype in cache.builtin_dtypes:
@@ -391,6 +428,8 @@
     name = interp_attrproperty('name', cls=W_Dtype),
     fields = GetSetProperty(W_Dtype.descr_get_fields),
     names = GetSetProperty(W_Dtype.descr_get_names),
+    subdtype = GetSetProperty(W_Dtype.descr_get_subdtype),
+    base = GetSetProperty(W_Dtype.descr_get_base),
 )
 W_Dtype.typedef.acceptable_as_base_class = False
 
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
@@ -21,7 +21,7 @@
 from rpython.rlib.rstring import StringBuilder
 from pypy.module.micronumpy.arrayimpl.base import BaseArrayImplementation
 
-def _find_shape(space, w_size):
+def _find_shape(space, w_size, dtype):
     if space.is_none(w_size):
         return []
     if space.isinstance_w(w_size, space.w_int):
@@ -29,6 +29,7 @@
     shape = []
     for w_item in space.fixedview(w_size):
         shape.append(space.int_w(w_item))
+    shape += dtype.shape
     return shape[:]
 
 class __extend__(W_NDimArray):
@@ -829,7 +830,7 @@
                              space.wrap("unsupported param"))
     dtype = space.interp_w(interp_dtype.W_Dtype,
           space.call_function(space.gettypefor(interp_dtype.W_Dtype), w_dtype))
-    shape = _find_shape(space, w_shape)
+    shape = _find_shape(space, w_shape, dtype)
     if not shape:
         return W_NDimArray.new_scalar(space, dtype)
     return W_NDimArray.from_shape(shape, dtype)
@@ -842,10 +843,10 @@
     """
     from rpython.rtyper.lltypesystem import rffi
     from rpython.rlib.rawstorage import RAW_STORAGE_PTR
-    shape = _find_shape(space, w_shape)
     storage = rffi.cast(RAW_STORAGE_PTR, addr)
     dtype = space.interp_w(interp_dtype.W_Dtype,
                            space.call_function(space.gettypefor(interp_dtype.W_Dtype), w_dtype))
+    shape = _find_shape(space, w_shape, dtype)
     return W_NDimArray.from_shape_and_storage(shape, storage, dtype)
 
 W_NDimArray.typedef = TypeDef(
@@ -1029,7 +1030,7 @@
     dtype = space.interp_w(interp_dtype.W_Dtype,
         space.call_function(space.gettypefor(interp_dtype.W_Dtype), w_dtype)
     )
-    shape = _find_shape(space, w_shape)
+    shape = _find_shape(space, w_shape, dtype)
     if not shape:
         return W_NDimArray.new_scalar(space, dtype, space.wrap(0))
     return space.wrap(W_NDimArray.from_shape(shape, dtype=dtype, order=order))
@@ -1039,7 +1040,7 @@
     dtype = space.interp_w(interp_dtype.W_Dtype,
         space.call_function(space.gettypefor(interp_dtype.W_Dtype), w_dtype)
     )
-    shape = _find_shape(space, w_shape)
+    shape = _find_shape(space, w_shape, dtype)
     if not shape:
         return W_NDimArray.new_scalar(space, dtype, space.wrap(0))
     arr = W_NDimArray.from_shape(shape, dtype=dtype, order=order)
diff --git a/pypy/module/micronumpy/iter.py b/pypy/module/micronumpy/iter.py
--- a/pypy/module/micronumpy/iter.py
+++ b/pypy/module/micronumpy/iter.py
@@ -32,13 +32,13 @@
 shape dimension
   which is back 25 and forward 1,
   which is x.strides[1] * (x.shape[1] - 1) + x.strides[0]
-so if we precalculate the overflow backstride as 
+so if we precalculate the overflow backstride as
 [x.strides[i] * (x.shape[i] - 1) for i in range(len(x.shape))]
 we can go faster.
 All the calculations happen in next()
 
 next_skip_x() tries to do the iteration for a number of steps at once,
-but then we cannot gaurentee that we only overflow one single shape 
+but then we cannot gaurentee that we only overflow one single shape
 dimension, perhaps we could overflow times in one big step.
 """
 
@@ -170,7 +170,8 @@
         self.dtype.setitem(self.array, self.offset, elem)
 
     def getitem(self):
-        return self.dtype.getitem(self.array, self.offset)
+        item = self.dtype.getitem(self.array, self.offset)
+        return item
 
     def getitem_bool(self):
         return self.dtype.getitem_bool(self.array, self.offset)
@@ -288,12 +289,13 @@
         self.dim = dim
         self.array = array
         self.dtype = array.dtype
-        
+
     def setitem(self, elem):
         self.dtype.setitem(self.array, self.offset, elem)
 
     def getitem(self):
-        return self.dtype.getitem(self.array, self.offset)
+        item = self.dtype.getitem(self.array, self.offset)
+        return item
 
     @jit.unroll_safe
     def next(self):
diff --git a/pypy/module/micronumpy/test/test_dtypes.py b/pypy/module/micronumpy/test/test_dtypes.py
--- a/pypy/module/micronumpy/test/test_dtypes.py
+++ b/pypy/module/micronumpy/test/test_dtypes.py
@@ -275,7 +275,7 @@
         from numpypy import array, dtype
         from cPickle import loads, dumps
         a = array([1,2,3])
-        if self.ptr_size == 8:
+         if self.ptr_size == 8:
             assert a.dtype.__reduce__() == (dtype, ('i8', 0, 1), (3, '<', None, None, None, -1, -1, 0))
         else:
             assert a.dtype.__reduce__() == (dtype, ('i4', 0, 1), (3, '<', None, None, None, -1, -1, 0))
@@ -726,7 +726,7 @@
         x = int8(42).ravel()
         assert x.dtype == int8
         assert (x == array(42)).all()
-        
+
 
 
 class AppTestStrUnicodeDtypes(BaseNumpyAppTest):
@@ -781,6 +781,7 @@
         assert d.num == 20
         assert d.itemsize == 20
         assert d.kind == 'V'
+        assert d.base == d
         assert d.type is void
         assert d.char == 'V'
         assert d.names == ("x", "y", "z", "value")
@@ -793,6 +794,27 @@
         d = dtype({'names': ['a', 'b', 'c'],
                    })
 
+    def test_create_subarrays(self):
+        from numpypy import dtype
+        d = dtype([("x", "float", (2,)), ("y", "int", (2,))])
+        assert d.itemsize == 32
+        assert d.name == "void256"
+        keys = d.fields.keys()
+        assert "x" in keys
+        assert "y" in keys
+        assert d["x"].shape == (2,)
+        assert d["x"].itemsize == 16
+        e = dtype([("x", "float", 2), ("y", "int", 2)])
+        assert e.fields.keys() == keys
+        assert e['x'].shape == (2,)
+
+        dt = dtype((float, 10))
+        assert dt.shape == (10,)
+        assert dt.kind == 'V'
+        assert dt.fields == None
+        assert dt.subdtype == (dtype(float), (10,))
+        assert dt.base == dtype(float)
+
 class AppTestNotDirect(BaseNumpyAppTest):
     def setup_class(cls):
         BaseNumpyAppTest.setup_class.im_func(cls)
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
@@ -18,10 +18,12 @@
         def get_element_size():
             return 1
 
+    def __init__(self):
+        self.base = self
+
     def get_size(self):
         return 1
 
-
 def create_slice(a, chunks):
     return Chunks(chunks).apply(W_NDimArray(a)).implementation
 
@@ -2699,6 +2701,56 @@
         assert a[0]['y'] == 2
         assert a[1]['y'] == 1
 
+    def test_subarrays(self):
+        from numpypy import dtype, array, zeros
+
+        d = dtype([("x", "int", 3), ("y", "float", 5)])
+        a = array([([1, 2, 3], [0.5, 1.5, 2.5, 3.5, 4.5]), ([4, 5, 6], [5.5, 6.5, 7.5, 8.5, 9.5])], dtype=d)
+
+        assert (a[0]["x"] == [1, 2, 3]).all()
+        assert (a[0]["y"] == [0.5, 1.5, 2.5, 3.5, 4.5]).all()
+        assert (a[1]["x"] == [4, 5, 6]).all()
+        assert (a[1]["y"] == [5.5, 6.5, 7.5, 8.5, 9.5]).all()
+
+        a[0]["x"][0] = 200
+        assert a[0]["x"][0] == 200
+
+        d = dtype([("x", "int", (2, 3))])
+        a = array([([[1, 2, 3], [4, 5, 6]],)], dtype=d)
+
+        assert a[0]["x"].dtype == dtype("int64")
+        assert a[0]["x"][0].dtype == dtype("int64")
+
+        assert (a[0]["x"][0] == [1, 2, 3]).all()
+        assert (a[0]["x"] == [[1, 2, 3], [4, 5, 6]]).all()
+
+        d = dtype((float, (10, 10)))
+        a = zeros((3,3), dtype=d)
+        assert a[0, 0].shape == (10, 10)
+        assert a.shape == (3, 3, 10, 10)
+        a[0, 0] = 500
+        assert (a[0, 0, 0] == 500).all()
+        assert a[0, 0, 0].shape == (10,)
+
+    def test_multidim_subarray(self):
+        from numpypy import dtype, array
+
+        d = dtype([("x", "int", (2, 3))])
+        a = array([([[1, 2, 3], [4, 5, 6]],)], dtype=d)
+
+        assert a[0]["x"].dtype == dtype("int64")
+        assert a[0]["x"][0].dtype == dtype("int64")
+
+        assert (a[0]["x"][0] == [1, 2, 3]).all()
+        assert (a[0]["x"] == [[1, 2, 3], [4, 5, 6]]).all()
+
+    def test_list_record(self):
+        from numpypy import dtype, array
+
+        d = dtype([("x", "int", 3), ("y", "float", 5)])
+        a = array([([1, 2, 3], [0.5, 1.5, 2.5, 3.5, 4.5]), ([4, 5, 6], [5.5, 6.5, 7.5, 8.5, 9.5])], dtype=d)
+
+        assert len(list(a[0])) == 2
 
 class AppTestPyPy(BaseNumpyAppTest):
     def setup_class(cls):
diff --git a/pypy/module/micronumpy/types.py b/pypy/module/micronumpy/types.py
--- a/pypy/module/micronumpy/types.py
+++ b/pypy/module/micronumpy/types.py
@@ -3,7 +3,9 @@
 
 from pypy.interpreter.error import OperationError
 from pypy.module.micronumpy import interp_boxes
+from pypy.module.micronumpy import support
 from pypy.module.micronumpy.arrayimpl.voidbox import VoidBoxStorage
+from pypy.module.micronumpy.arrayimpl.concrete import SliceArray
 from pypy.objspace.std.floatobject import float2string
 from pypy.objspace.std.complexobject import str_format
 from rpython.rlib import rfloat, clibffi, rcomplex
@@ -1076,7 +1078,7 @@
 
     def to_builtin_type(self, space, box):
         real,imag = self.for_computation(self.unbox(box))
-        return space.newcomplex(real, imag) 
+        return space.newcomplex(real, imag)
 
     def read_bool(self, arr, i, offset):
         v = self.for_computation(self._read(arr.storage, i, offset))
@@ -1217,7 +1219,7 @@
 
     @raw_binary_op
     def le(self, v1, v2):
-        return self._lt(v1, v2) or self._eq(v1, v2) 
+        return self._lt(v1, v2) or self._eq(v1, v2)
 
     @raw_binary_op
     def gt(self, v1, v2):
@@ -1225,7 +1227,7 @@
 
     @raw_binary_op
     def ge(self, v1, v2):
-        return self._lt(v2, v1) or self._eq(v2, v1) 
+        return self._lt(v2, v1) or self._eq(v2, v1)
 
     def _bool(self, v):
         return bool(v[0]) or bool(v[1])
@@ -1341,7 +1343,7 @@
             return rcomplex.c_div((v[0], -v[1]), (a2, 0.))
         except ZeroDivisionError:
             return rfloat.NAN, rfloat.NAN
- 
+
     # No floor, ceil, trunc in numpy for complex
     #@simple_unary_op
     #def floor(self, v):
@@ -1684,6 +1686,7 @@
         return space.wrap(self.to_str(box))
 
     def build_and_convert(self, space, mydtype, box):
+        assert isinstance(box, interp_boxes.W_GenericBox)
         if box.get_dtype(space).is_str_or_unicode():
             arg = box.get_dtype(space).itemtype.to_str(box)
         else:
@@ -1696,10 +1699,68 @@
         for j in range(i + 1, self.size):
             arr.storage[j] = '\x00'
         return interp_boxes.W_StringBox(arr,  0, arr.dtype)
-        
+
 class VoidType(BaseType, BaseStringType):
     T = lltype.Char
 
+    def _coerce(self, space, arr, ofs, dtype, w_items, shape):
+        items_w = space.fixedview(w_items)
+        for i in range(len(items_w)):
+            subdtype = dtype.subdtype
+            itemtype = subdtype.itemtype
+            if space.len_w(shape) <= 1:
+                w_box = itemtype.coerce(space, dtype.subdtype, items_w[i])
+                itemtype.store(arr, 0, ofs, w_box)
+                ofs += itemtype.get_element_size()
+            else:
+                size = 1
+                for dimension in shape[1:]:
+                    size *= dimension
+                size *= itemtype.get_element_size()
+                for w_item in items_w:
+                    self._coerce(space, arr, ofs, dtype, w_items, shape[1:])
+                    ofs += size
+        return arr
+
+    def _coerce(self, space, arr, ofs, dtype, w_items, shape):
+        # TODO: Make sure the shape and the array match
+        items_w = space.fixedview(w_items)
+        subdtype = dtype.subdtype
+        itemtype = subdtype.itemtype
+        if len(shape) <= 1:
+            for i in range(len(items_w)):
+                w_box = itemtype.coerce(space, dtype.subdtype, items_w[i])
+                itemtype.store(arr, 0, ofs, w_box)
+                ofs += itemtype.get_element_size()
+        else:
+            for w_item in items_w:
+                size = 1
+                for dimension in shape[1:]:
+                    size *= dimension
+                size *= itemtype.get_element_size()
+                self._coerce(space, arr, ofs, dtype, w_item, shape[1:])
+                ofs += size
+
+    def coerce(self, space, dtype, w_items):
+        arr = VoidBoxStorage(self.size, dtype)
+        self._coerce(space, arr, 0, dtype, w_items, dtype.shape)
+        return interp_boxes.W_VoidBox(arr, 0, dtype)
+
+    @jit.unroll_safe
+    def store(self, arr, i, ofs, box):
+        assert isinstance(box, interp_boxes.W_VoidBox)
+        for k in range(self.get_element_size()):
+            arr.storage[k + ofs] = box.arr.storage[k + box.ofs]
+
+    def readarray(self, arr, i, offset, dtype=None):
+        from pypy.module.micronumpy.base import W_NDimArray
+        if dtype is None:
+            dtype = arr.dtype
+        strides, backstrides = support.calc_strides(dtype.shape, dtype.subdtype, arr.order)
+        implementation = SliceArray(i + offset, strides, backstrides,
+                             dtype.shape, arr, W_NDimArray(arr), dtype.subdtype)
+        return W_NDimArray(implementation)
+
 NonNativeVoidType = VoidType
 NonNativeStringType = StringType
 
@@ -1733,7 +1794,7 @@
         if not space.issequence_w(w_item):
             raise OperationError(space.w_TypeError, space.wrap(
                 "expected sequence"))
-        if len(self.offsets_and_fields) != space.int_w(space.len(w_item)):
+        if len(self.offsets_and_fields) != space.len_w(w_item):
             raise OperationError(space.w_ValueError, space.wrap(
                 "wrong length"))
         items_w = space.fixedview(w_item)
diff --git a/pypy/objspace/std/specialisedtupleobject.py b/pypy/objspace/std/specialisedtupleobject.py
--- a/pypy/objspace/std/specialisedtupleobject.py
+++ b/pypy/objspace/std/specialisedtupleobject.py
@@ -74,7 +74,7 @@
 
         def descr_eq(self, space, w_other):
             if not isinstance(w_other, W_AbstractTupleObject):
-                return space.w_NotImplementedError
+                return space.w_NotImplemented
             if not isinstance(w_other, cls):
                 if nValues != w_other.length():
                     return space.w_False
diff --git a/pypy/objspace/std/test/test_specialisedtupleobject.py b/pypy/objspace/std/test/test_specialisedtupleobject.py
--- a/pypy/objspace/std/test/test_specialisedtupleobject.py
+++ b/pypy/objspace/std/test/test_specialisedtupleobject.py
@@ -216,4 +216,4 @@
 
 
 class AppTestAll(test_tupleobject.AppTestW_TupleObject):
-    pass
+    spaceconfig = {"objspace.std.withspecialisedtuple": True}
diff --git a/pypy/objspace/std/test/test_tupleobject.py b/pypy/objspace/std/test/test_tupleobject.py
--- a/pypy/objspace/std/test/test_tupleobject.py
+++ b/pypy/objspace/std/test/test_tupleobject.py
@@ -399,3 +399,11 @@
         assert ((5,) != (N,)) is True
         assert ((5,) >  (N,)) is False
         assert ((5,) >= (N,)) is False
+
+    def test_eq_other_type(self):
+        assert (() == object()) is False
+        assert ((1,) == object()) is False
+        assert ((1, 2) == object()) is False
+        assert (() != object()) is True
+        assert ((1,) != object()) is True
+        assert ((1, 2) != object()) is True
diff --git a/rpython/jit/metainterp/pyjitpl.py b/rpython/jit/metainterp/pyjitpl.py
--- a/rpython/jit/metainterp/pyjitpl.py
+++ b/rpython/jit/metainterp/pyjitpl.py
@@ -621,7 +621,8 @@
         tobox = self.metainterp.heapcache.getfield(box, fielddescr)
         if tobox is valuebox:
             return
-        self.execute_with_descr(rop.SETFIELD_GC, fielddescr, box, valuebox)
+        if tobox is not None or not self.metainterp.heapcache.is_unescaped(box) or not isinstance(valuebox, Const) or valuebox.nonnull():
+            self.execute_with_descr(rop.SETFIELD_GC, fielddescr, box, valuebox)
         self.metainterp.heapcache.setfield(box, valuebox, fielddescr)
     opimpl_setfield_gc_i = _opimpl_setfield_gc_any
     opimpl_setfield_gc_r = _opimpl_setfield_gc_any
diff --git a/rpython/jit/metainterp/test/test_tracingopts.py b/rpython/jit/metainterp/test/test_tracingopts.py
--- a/rpython/jit/metainterp/test/test_tracingopts.py
+++ b/rpython/jit/metainterp/test/test_tracingopts.py
@@ -645,3 +645,20 @@
         res = self.interp_operations(fn, [1])
         assert res == -1
         self.check_operations_history(guard_class=0)
+
+    def test_dont_record_setfield_gc_zeros(self):
+        class A(object):
+            pass
+
+        def make_a():
+            return A()
+        make_a._dont_inline_ = True
+
+        def fn(n):
+            a = make_a()
+            a.x = jit.promote(n)
+            return a.x
+
+        res = self.interp_operations(fn, [0])
+        assert res == 0
+        self.check_operations_history(setfield_gc=0)


More information about the pypy-commit mailing list