Author: Richard Plangger <[email protected]>
Branch: py3.5-memoryview
Changeset: r86569:5ef2fe0ae4aa
Date: 2016-08-26 16:32 +0200
http://bitbucket.org/pypy/pypy/changeset/5ef2fe0ae4aa/
Log: work in progress for memoryview.cast, there is still one issue,
memoryview modifies the format field othe underlying Py_buffer
struct
diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -1439,12 +1439,6 @@
BUF_FULL_RO = BUF_INDIRECT | BUF_FORMAT
BUF_FULL = BUF_INDIRECT | BUF_FORMAT | BUF_WRITABLE
- MEMORYVIEW_MAX_DIM = 64
- MEMORYVIEW_C = 0x0002
- MEMORYVIEW_FORTRAN = 0x0004
- MEMORYVIEW_SCLAR = 0x0008
- MEMORYVIEW_PIL = 0x0010
-
def check_buf_flags(self, flags, readonly):
if readonly and flags & self.BUF_WRITABLE == self.BUF_WRITABLE:
raise oefmt(self.w_BufferError, "Object is not writable.")
diff --git a/pypy/objspace/std/memoryobject.py
b/pypy/objspace/std/memoryobject.py
--- a/pypy/objspace/std/memoryobject.py
+++ b/pypy/objspace/std/memoryobject.py
@@ -11,6 +11,14 @@
from pypy.interpreter.gateway import interp2app
from pypy.interpreter.typedef import TypeDef, GetSetProperty,
make_weakref_descr
from pypy.module.struct.formatiterator import UnpackFormatIterator,
PackFormatIterator
+from rpython.rlib.unroll import unrolling_iterable
+
+MEMORYVIEW_MAX_DIM = 64
+MEMORYVIEW_SCALAR = 0x0001
+MEMORYVIEW_C = 0x0002
+MEMORYVIEW_FORTRAN = 0x0004
+MEMORYVIEW_SCALAR = 0x0008
+MEMORYVIEW_PIL = 0x0010
class W_MemoryView(W_Root):
@@ -18,12 +26,24 @@
an interp-level buffer.
"""
- def __init__(self, buf, format='B', itemsize=1):
+ def __init__(self, buf, format=None, itemsize=1):
assert isinstance(buf, Buffer)
self.buf = buf
self._hash = -1
self.format = format
self.itemsize = itemsize
+ self.flags = 0
+ self._init_flags()
+
+ def getformat(self):
+ # memoryview needs to modify the field 'format', to prevent the
modification
+ # of the buffer, we save the new format here!
+ if self.format is None:
+ return self.buf.getformat()
+ return self.format
+
+ def setformat(self, value):
+ self.format = value
def buffer_w_ex(self, space, flags):
self._check_released(space)
@@ -154,11 +174,11 @@
# TODO: this probably isn't very fast
buf = SubBuffer(self.buf, start, self.itemsize)
fmtiter = UnpackFormatIterator(space, buf)
- fmtiter.interpret(self.format)
+ fmtiter.interpret(self.getformat())
return fmtiter.result_w[0]
elif step == 1:
buf = SubBuffer(self.buf, start, size)
- return W_MemoryView(buf, self.format, self.itemsize)
+ return W_MemoryView(buf, self.getformat(), self.itemsize)
else:
buf = SubBuffer(self.buf, start, size)
return W_MemoryView(buf)
@@ -193,7 +213,7 @@
except StructError as e:
raise oefmt(space.w_TypeError,
"memoryview: invalid type for format '%s'",
- self.format)
+ self.getformat())
self.buf.setslice(start, fmtiter.result.build())
elif step == 1:
value = space.buffer_w(w_obj, space.BUF_CONTIG_RO)
@@ -210,7 +230,7 @@
def w_get_format(self, space):
self._check_released(space)
- return space.wrap(self.buf.getformat())
+ return space.wrap(self.getformat())
def w_get_itemsize(self, space):
self._check_released(space)
@@ -318,7 +338,6 @@
return False
def descr_cast(self, space, w_format, w_shape=None):
- # XXX fixme. does not do anything near cpython (see memoryobjet.c
memory_cast)
self._check_released(space)
if not space.isinstance_w(w_format, space.w_unicode):
@@ -326,15 +345,15 @@
space.wrap("memoryview: format argument must be a string"))
fmt = space.str_w(w_format)
- view = self.buf
+ buf = self.buf
ndim = 1
- if not memory_view_c_contiguous(space, view.flags):
+ if not memory_view_c_contiguous(space, self.flags):
raise OperationError(space.w_TypeError, \
space.wrap("memoryview: casts are restricted" \
" to C-contiguous views"))
- if (w_shape or view.getndim() != 1) and self._zero_in_shape():
+ if (w_shape or buf.getndim() != 1) and self._zero_in_shape():
raise OperationError(space.w_TypeError, \
space.wrap("memoryview: cannot casts view with" \
" zeros in shape or strides"))
@@ -352,60 +371,89 @@
raise OperationError(space.w_TypeError, \
space.wrap("memoryview: cast must be 1D -> ND or ND ->
1D"))
+ mv = W_MemoryView(buf, fmt, itemsize)
+ origfmt = mv.getformat()
+ mv._cast_to_1D(space, origfmt, fmt, itemsize)
+ if w_shape:
shape = [space.int_w(w_obj) for w_obj in
w_shape.fixedview_unroll()]
- return W_MemoryView(Buffer.cast_to(buf, itemsize, shape))
-
- return W_MemoryView(Buffer.cast_to(buf, itemsize, None))
+ mv._cast_to_ND(space, shape, dim)
+ return mv
def _init_flags(self):
- # TODO move to buffer.py
- view = self.buf
- ndim = view.ndim
+ buf = self.buf
+ ndim = buf.ndim
flags = 0
if ndim == 0:
- flags |= space.MEMORYVIEW_SCALAR | space.MEMORYVIEW_C |
space.MEMORYVIEW_FORTRAN
+ flags |= MEMORYVIEW_SCALAR | MEMORYVIEW_C | MEMORYVIEW_FORTRAN
if ndim == 1:
- if view.shape[0] == 1 and view.strides[0] == view.itemsize:
- flags |= space.MEMORYVIEW_C | space.MEMORYVIEW_SCALAR
- if view.is_contiguous('C'):
- flags |= space.MEMORYVIEW_C
- elif view.is_contiguous('F'):
- flags |= space.MEMORYVIEW_SCALAR
+ shape = buf.getshape()
+ strides = buf.getstrides()
+ if len(shape) > 0 and shape[0] == 1 and \
+ len(strides) > 0 and strides[0] == buf.getitemsize():
+ flags |= MEMORYVIEW_C | MEMORYVIEW_SCALAR
+ if buf.is_contiguous('C'):
+ flags |= MEMORYVIEW_C
+ elif buf.is_contiguous('F'):
+ flags |= MEMORYVIEW_FORTRAN
# XXX missing suboffsets
- view.flags = flags
+ self.flags = flags
- def _cast_to_1D(self, space, fmt):
- itemsize = self.get_native_fmtchar(fmt)
+ def _cast_to_1D(self, space, origfmt, fmt, itemsize):
buf = self.buf
if itemsize < 0:
- raise OperationError(space.w_ValueError, "memoryview: destination"
\
+ raise oefmt(space.w_ValueError, "memoryview: destination" \
" format must be a native single character format
prefixed" \
" with an optional '@'")
- buffmt = buf.getformat()
- if self.get_native_fmtchar(buffmt) < 0 or \
- (not is_byte_format(fmt) and not is_byte_format(buffmt)):
- raise OperationError(space.w_TypeError,
+ if self.get_native_fmtchar(origfmt) < 0 or \
+ (not is_byte_format(fmt) and not is_byte_format(origfmt)):
+ raise oefmt(space.w_TypeError,
"memoryview: cannot cast between" \
" two non-byte formats")
if buf.getlength() % itemsize != 0:
- raise OperationError(space.w_TypeError,
+ raise oefmt(space.w_TypeError,
"memoryview: length is not a multiple of itemsize")
- buf.format = get_native_fmtstr(fmt)
- if not buffmt:
- raise OperationError(space.w_RuntimeError,
+ newfmt = self.get_native_fmtstr(fmt)
+ if not newfmt:
+ raise oefmt(space.w_RuntimeError,
"memoryview: internal error")
- buf.itemsize = itemsize
- buf.ndim = 1
- buf.shape[0] = buf.length / buf.itemsize
- buf.srides[0] = buf.itemsize
+ self.setformat(newfmt)
+ self.itemsize = itemsize
+ self.ndim = 1
+ self.shape = [buf.getlength() / buf.getitemsize()]
+ self.srides = [buf.getitemsize()]
# XX suboffsets
- mv._init_flags()
+ self._init_flags()
+
+ def get_native_fmtstr(self, fmt):
+ lenfmt = len(fmt)
+ nat = False
+ if lenfmt == 0:
+ return None
+ elif lenfmt == 1:
+ format = fmt[0] # fine!
+ elif lenfmt == 2:
+ if fmt[0] == '@':
+ nat = True
+ format = fmt[1]
+ else:
+ return None
+ else:
+ return None
+
+ chars = ['c','b','B','h','H','i','I','l','L','q',
+ 'Q','n','N','f','d','?','P']
+ for c in unrolling_iterable(chars):
+ if c == format:
+ if nat: return '@'+c
+ else: return c
+
+ return None
def _cast_to_ND(self, space, shape, ndim):
pass
@@ -419,7 +467,7 @@
return char == 'b' or char == 'B' or char == 'c'
def memory_view_c_contiguous(space, flags):
- return flags & (space.BUF_CONTIG_RO|space.MEMORYVIEW_C) != 0
+ return flags & (space.BUF_CONTIG_RO|MEMORYVIEW_C) != 0
W_MemoryView.typedef = TypeDef(
"memoryview",
diff --git a/pypy/objspace/std/test/test_memoryobject.py
b/pypy/objspace/std/test/test_memoryobject.py
--- a/pypy/objspace/std/test/test_memoryobject.py
+++ b/pypy/objspace/std/test/test_memoryobject.py
@@ -177,11 +177,10 @@
def __init__(self, space, w_arr, w_dim, w_fmt, \
w_itemsize, w_strides, w_shape):
self.space = space
- self.flags = space.MEMORYVIEW_C
self.w_arr = w_arr
self.arr = []
self.ndim = space.int_w(w_dim)
- self.fmt = space.str_w(w_fmt)
+ self.format = space.str_w(w_fmt)
self.itemsize = space.int_w(w_itemsize)
self.strides = []
for w_i in w_strides.getitems_unroll():
@@ -204,6 +203,8 @@
def getslice(self, start, stop, step, size):
items = []
+ if size == 0:
+ return ''
bytecount = (stop - start)
# data is stores as list of ints, thus this gets around the
# issue that one cannot advance in bytes
@@ -214,10 +215,10 @@
return ''.join(items)
def getformat(self):
- return self.fmt
+ return self.format
def getitem(self, index):
- return struct.pack(self.fmt, self.data[index])
+ return struct.pack(self.format, self.data[index])
def getlength(self):
return len(self.data) * self.itemsize
@@ -234,6 +235,9 @@
def getshape(self):
return self.shape
+ def is_contiguous(self, format):
+ return format == 'C'
+
class W_MockArray(W_Root):
def __init__(self, w_list, w_dim, w_fmt, w_size, w_strides, w_shape):
self.w_list = w_list
@@ -295,9 +299,29 @@
assert view[0,0,0] == 1
assert view[-1,2,0] == 6
+ def test_cast_non_byte(self):
+ empty = self.MockArray([], dim=1, fmt='i', size=4, strides=[1],
shape=[1])
+ view = memoryview(empty)
+ try:
+ view.cast('l')
+ assert False, "i -> l not possible. buffer must be byte format"
+ except TypeError:
+ pass
+
def test_cast_empty(self):
- empty = self.MockArray([], dim=1, fmt='i', size=4, strides=[1],
shape=[1])
+ empty = self.MockArray([], dim=1, fmt='b', size=1, strides=[1],
shape=[1])
view = memoryview(empty)
cview = view.cast('i')
assert cview.tobytes() == b''
+ assert cview.tolist() == []
+ assert view.format == 'b'
+ assert cview.format == 'i'
+ #
+ assert cview.cast('i').cast('b').cast('i').tolist() == []
+ #
+ try:
+ cview = view.cast('i')
+ assert False, "cannot cast between two non byte formats!"
+ except TypeError:
+ pass
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit