/pypy/module/micronumpy/concrete.py
Python | 706 lines | 594 code | 82 blank | 30 comment | 118 complexity | 94b9c31589b69e91cf895df988321f87 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
- from pypy.interpreter.error import oefmt
- from rpython.rlib import jit, rgc
- from rpython.rlib.rarithmetic import ovfcheck
- from rpython.rlib.listsort import make_timsort_class
- from rpython.rlib.buffer import Buffer
- from rpython.rlib.debug import make_sure_not_resized
- from rpython.rlib.rawstorage import alloc_raw_storage, free_raw_storage, \
- raw_storage_getitem, raw_storage_setitem, RAW_STORAGE
- from rpython.rtyper.lltypesystem import rffi, lltype, llmemory
- from pypy.module.micronumpy import support, loop, constants as NPY
- from pypy.module.micronumpy.base import convert_to_array, W_NDimArray, \
- ArrayArgumentException, W_NumpyObject
- from pypy.module.micronumpy.iterators import ArrayIter
- from pypy.module.micronumpy.strides import (
- IntegerChunk, SliceChunk, NewAxisChunk, EllipsisChunk, BooleanChunk,
- new_view, calc_strides, calc_new_strides, shape_agreement,
- calculate_broadcast_strides, calc_backstrides, calc_start, is_c_contiguous,
- is_f_contiguous)
- from rpython.rlib.objectmodel import keepalive_until_here
- TimSort = make_timsort_class()
- class StrideSort(TimSort):
- '''
- argsort (return the indices to sort) a list of strides
- '''
- def __init__(self, rangelist, strides, order):
- self.strides = strides
- self.order = order
- TimSort.__init__(self, rangelist)
- def lt(self, a, b):
- if self.order == NPY.CORDER:
- return self.strides[a] <= self.strides[b]
- return self.strides[a] < self.strides[b]
- class BaseConcreteArray(object):
- _immutable_fields_ = ['dtype?', 'storage', 'start', 'size', 'shape[*]',
- 'strides[*]', 'backstrides[*]', 'order', 'gcstruct',
- 'flags']
- start = 0
- parent = None
- flags = 0
- # JIT hints that length of all those arrays is a constant
- def get_shape(self):
- shape = self.shape
- jit.hint(len(shape), promote=True)
- return shape
- def get_strides(self):
- strides = self.strides
- jit.hint(len(strides), promote=True)
- return strides
- def get_backstrides(self):
- backstrides = self.backstrides
- jit.hint(len(backstrides), promote=True)
- return backstrides
- def get_flags(self):
- return self.flags
- def getitem(self, index):
- return self.dtype.read(self, index, 0)
- def getitem_bool(self, index):
- return self.dtype.read_bool(self, index, 0)
- def setitem(self, index, value):
- self.dtype.store(self, index, 0, value)
- @jit.unroll_safe
- def setslice(self, space, arr):
- if arr.get_size() == 1:
- # we can always set self[:] = scalar
- pass
- elif len(arr.get_shape()) > len(self.get_shape()):
- # record arrays get one extra dimension
- if not self.dtype.is_record() or \
- len(arr.get_shape()) > len(self.get_shape()) + 1:
- raise oefmt(space.w_ValueError,
- "could not broadcast input array from shape "
- "(%s) into shape (%s)",
- ','.join([str(x) for x in arr.get_shape()]),
- ','.join([str(x) for x in self.get_shape()]),
- )
- shape = shape_agreement(space, self.get_shape(), arr)
- impl = arr.implementation
- if impl.storage == self.storage:
- impl = impl.copy(space)
- loop.setslice(space, shape, self, impl)
- def get_size(self):
- return self.size // self.dtype.elsize
- def get_storage_size(self):
- return self.size
- def reshape(self, orig_array, new_shape, order=NPY.ANYORDER):
- # Since we got to here, prod(new_shape) == self.size
- order = support.get_order_as_CF(self.order, order)
- new_strides = None
- if self.size == 0:
- new_strides, _ = calc_strides(new_shape, self.dtype, order)
- else:
- if len(self.get_shape()) == 0:
- new_strides = [self.dtype.elsize] * len(new_shape)
- else:
- new_strides = calc_new_strides(new_shape, self.get_shape(),
- self.get_strides(), order)
- if new_strides is None or len(new_strides) != len(new_shape):
- return None
- if new_strides is not None:
- # We can create a view, strides somehow match up.
- new_backstrides = calc_backstrides(new_strides, new_shape)
- assert isinstance(orig_array, W_NDimArray) or orig_array is None
- return SliceArray(self.start, new_strides, new_backstrides,
- new_shape, self, orig_array)
- return None
- def get_view(self, space, orig_array, dtype, new_shape, strides=None, backstrides=None):
- if not strides:
- strides, backstrides = calc_strides(new_shape, dtype,
- self.order)
- return SliceArray(self.start, strides, backstrides, new_shape,
- self, orig_array, dtype=dtype)
- def get_real(self, space, orig_array):
- strides = self.get_strides()
- backstrides = self.get_backstrides()
- if self.dtype.is_complex():
- dtype = self.dtype.get_float_dtype(space)
- return SliceArray(self.start, strides, backstrides,
- self.get_shape(), self, orig_array, dtype=dtype)
- return SliceArray(self.start, strides, backstrides,
- self.get_shape(), self, orig_array)
- def set_real(self, space, orig_array, w_value):
- tmp = self.get_real(space, orig_array)
- tmp.setslice(space, convert_to_array(space, w_value))
- def get_imag(self, space, orig_array):
- strides = self.get_strides()
- backstrides = self.get_backstrides()
- if self.dtype.is_complex():
- dtype = self.dtype.get_float_dtype(space)
- return SliceArray(self.start + dtype.elsize, strides, backstrides,
- self.get_shape(), self, orig_array, dtype=dtype)
- impl = NonWritableArray(self.get_shape(), self.dtype, self.order,
- strides, backstrides)
- if not self.dtype.is_flexible():
- impl.fill(space, self.dtype.box(0))
- return impl
- def set_imag(self, space, orig_array, w_value):
- tmp = self.get_imag(space, orig_array)
- tmp.setslice(space, convert_to_array(space, w_value))
- # -------------------- applevel get/setitem -----------------------
- @jit.unroll_safe
- def _lookup_by_index(self, space, view_w):
- item = self.start
- strides = self.get_strides()
- for i, w_index in enumerate(view_w):
- if space.isinstance_w(w_index, space.w_slice):
- raise IndexError
- idx = support.index_w(space, w_index)
- if idx < 0:
- idx = self.get_shape()[i] + idx
- if idx < 0 or idx >= self.get_shape()[i]:
- raise oefmt(space.w_IndexError,
- "index %d is out of bounds for axis %d with size "
- "%d", idx, i, self.get_shape()[i])
- item += idx * strides[i]
- return item
- @jit.unroll_safe
- def _lookup_by_unwrapped_index(self, space, lst):
- item = self.start
- shape = self.get_shape()
- strides = self.get_strides()
- assert len(lst) == len(shape)
- for i, idx in enumerate(lst):
- if idx < 0:
- idx = shape[i] + idx
- if idx < 0 or idx >= shape[i]:
- raise oefmt(space.w_IndexError,
- "index %d is out of bounds for axis %d with size "
- "%d", idx, i, self.get_shape()[i])
- item += idx * strides[i]
- return item
- def getitem_index(self, space, index):
- return self.getitem(self._lookup_by_unwrapped_index(space, index))
- def setitem_index(self, space, index, value):
- self.setitem(self._lookup_by_unwrapped_index(space, index), value)
- @jit.unroll_safe
- def _single_item_index(self, space, w_idx):
- """ Return an index of single item if possible, otherwise raises
- IndexError
- """
- if (space.isinstance_w(w_idx, space.w_str) or
- space.isinstance_w(w_idx, space.w_slice) or
- space.is_w(w_idx, space.w_None)):
- raise IndexError
- if isinstance(w_idx, W_NDimArray) and not w_idx.is_scalar():
- raise ArrayArgumentException
- shape = self.get_shape()
- shape_len = len(shape)
- view_w = None
- if space.isinstance_w(w_idx, space.w_list):
- raise ArrayArgumentException
- if space.isinstance_w(w_idx, space.w_tuple):
- view_w = space.fixedview(w_idx)
- if len(view_w) != shape_len:
- raise IndexError
- # check for arrays
- for w_item in view_w:
- if (isinstance(w_item, W_NDimArray) or
- space.isinstance_w(w_item, space.w_list)):
- raise ArrayArgumentException
- elif space.is_w(w_item, space.w_Ellipsis):
- raise IndexError
- return self._lookup_by_index(space, view_w)
- if shape_len == 0:
- raise oefmt(space.w_IndexError, "too many indices for array")
- elif shape_len > 1:
- raise IndexError
- idx = support.index_w(space, w_idx)
- return self._lookup_by_index(space, [space.wrap(idx)])
- @jit.unroll_safe
- def _prepare_slice_args(self, space, w_idx):
- from pypy.module.micronumpy import boxes
- if space.isinstance_w(w_idx, space.w_str):
- raise oefmt(space.w_IndexError, "only integers, slices (`:`), "
- "ellipsis (`...`), numpy.newaxis (`None`) and integer or "
- "boolean arrays are valid indices")
- if space.isinstance_w(w_idx, space.w_slice):
- if len(self.get_shape()) == 0:
- raise oefmt(space.w_ValueError, "cannot slice a 0-d array")
- return [SliceChunk(w_idx), EllipsisChunk()]
- elif space.isinstance_w(w_idx, space.w_int):
- return [IntegerChunk(w_idx), EllipsisChunk()]
- elif isinstance(w_idx, W_NDimArray) and w_idx.is_scalar():
- w_idx = w_idx.get_scalar_value().item(space)
- if not space.isinstance_w(w_idx, space.w_int) and \
- not space.isinstance_w(w_idx, space.w_bool):
- raise oefmt(space.w_IndexError,
- "arrays used as indices must be of integer (or "
- "boolean) type")
- return [IntegerChunk(w_idx), EllipsisChunk()]
- elif space.is_w(w_idx, space.w_None):
- return [NewAxisChunk(), EllipsisChunk()]
- result = []
- has_ellipsis = False
- has_filter = False
- for w_item in space.fixedview(w_idx):
- if space.is_w(w_item, space.w_Ellipsis):
- if has_ellipsis:
- # in CNumPy, this is only a deprecation warning
- raise oefmt(space.w_ValueError,
- "an index can only have a single Ellipsis (`...`); "
- "replace all but one with slices (`:`).")
- result.append(EllipsisChunk())
- has_ellipsis = True
- elif space.is_w(w_item, space.w_None):
- result.append(NewAxisChunk())
- elif space.isinstance_w(w_item, space.w_slice):
- result.append(SliceChunk(w_item))
- elif isinstance(w_item, W_NDimArray) and w_item.get_dtype().is_bool():
- if has_filter:
- # in CNumPy, the support for this is incomplete
- raise oefmt(space.w_ValueError,
- "an index can only have a single boolean mask; "
- "use np.take or create a sinlge mask array")
- has_filter = True
- result.append(BooleanChunk(w_item))
- elif isinstance(w_item, boxes.W_GenericBox):
- result.append(IntegerChunk(w_item.descr_int(space)))
- else:
- result.append(IntegerChunk(w_item))
- if not has_ellipsis:
- result.append(EllipsisChunk())
- return result
- def descr_getitem(self, space, orig_arr, w_index):
- try:
- item = self._single_item_index(space, w_index)
- return self.getitem(item)
- except IndexError:
- # not a single result
- chunks = self._prepare_slice_args(space, w_index)
- copy = False
- if isinstance(chunks[0], BooleanChunk):
- # numpy compatibility
- copy = True
- w_ret = new_view(space, orig_arr, chunks)
- if copy:
- w_ret = w_ret.descr_copy(space, space.wrap(w_ret.get_order()))
- return w_ret
- def descr_setitem(self, space, orig_arr, w_index, w_value):
- try:
- item = self._single_item_index(space, w_index)
- self.setitem(item, self.dtype.coerce(space, w_value))
- except IndexError:
- w_value = convert_to_array(space, w_value)
- chunks = self._prepare_slice_args(space, w_index)
- view = new_view(space, orig_arr, chunks)
- view.implementation.setslice(space, w_value)
- def transpose(self, orig_array, axes=None):
- if len(self.get_shape()) < 2:
- return self
- strides = []
- backstrides = []
- shape = []
- if axes is None:
- axes = range(len(self.get_shape()) - 1, -1, -1)
- for i in axes:
- strides.append(self.get_strides()[i])
- backstrides.append(self.get_backstrides()[i])
- shape.append(self.get_shape()[i])
- return SliceArray(self.start, strides,
- backstrides, shape, self, orig_array)
- def copy(self, space, order=NPY.ANYORDER):
- if order == NPY.ANYORDER:
- order = NPY.KEEPORDER
- return self.astype(space, self.dtype, order, copy=True)
- def create_iter(self, shape=None, backward_broadcast=False):
- if shape is not None and \
- support.product(shape) > support.product(self.get_shape()):
- r = calculate_broadcast_strides(self.get_strides(),
- self.get_backstrides(),
- self.get_shape(), shape,
- backward_broadcast)
- i = ArrayIter(self, support.product(shape), shape, r[0], r[1])
- else:
- i = ArrayIter(self, self.get_size(), self.shape,
- self.strides, self.backstrides)
- return i, i.reset()
- def swapaxes(self, space, orig_arr, axis1, axis2):
- shape = self.get_shape()[:]
- strides = self.get_strides()[:]
- backstrides = self.get_backstrides()[:]
- shape[axis1], shape[axis2] = shape[axis2], shape[axis1]
- strides[axis1], strides[axis2] = strides[axis2], strides[axis1]
- backstrides[axis1], backstrides[axis2] = backstrides[axis2], backstrides[axis1]
- return W_NDimArray.new_slice(space, self.start, strides,
- backstrides, shape, self, orig_arr)
- def nonzero(self, space, index_type):
- s = loop.count_all_true_concrete(self)
- box = index_type.itemtype.box
- nd = len(self.get_shape()) or 1
- w_res = W_NDimArray.from_shape(space, [s, nd], index_type)
- loop.nonzero(w_res, self, box)
- w_res = w_res.implementation.swapaxes(space, w_res, 0, 1)
- l_w = [w_res.descr_getitem(space, space.wrap(d)) for d in range(nd)]
- return space.newtuple(l_w)
- ##def get_storage(self):
- ## return self.storage
- ## use a safer context manager
- def __enter__(self):
- return self.storage
- def __exit__(self, typ, value, traceback):
- keepalive_until_here(self)
- def get_buffer(self, space, readonly):
- return ArrayBuffer(self, readonly)
- def astype(self, space, dtype, order, copy=True):
- # copy the general pattern of the strides
- # but make the array storage contiguous in memory
- shape = self.get_shape()
- strides = self.get_strides()
- if order not in (NPY.KEEPORDER, NPY.FORTRANORDER, NPY.CORDER):
- raise oefmt(space.w_ValueError, "Unknown order %d in astype", order)
- if len(strides) == 0:
- t_strides = []
- backstrides = []
- elif order in (NPY.FORTRANORDER, NPY.CORDER):
- t_strides, backstrides = calc_strides(shape, dtype, order)
- else:
- indx_array = range(len(strides))
- list_sorter = StrideSort(indx_array, strides, self.order)
- list_sorter.sort()
- t_elsize = dtype.elsize
- t_strides = strides[:]
- base = dtype.elsize
- for i in indx_array:
- t_strides[i] = base
- base *= shape[i]
- backstrides = calc_backstrides(t_strides, shape)
- order = support.get_order_as_CF(self.order, order)
- impl = ConcreteArray(shape, dtype, order, t_strides, backstrides)
- if copy:
- loop.setslice(space, impl.get_shape(), impl, self)
- return impl
- OBJECTSTORE = lltype.GcStruct('ObjectStore',
- ('length', lltype.Signed),
- ('step', lltype.Signed),
- ('storage', llmemory.Address),
- rtti=True)
- offset_of_storage = llmemory.offsetof(OBJECTSTORE, 'storage')
- offset_of_length = llmemory.offsetof(OBJECTSTORE, 'length')
- offset_of_step = llmemory.offsetof(OBJECTSTORE, 'step')
- V_OBJECTSTORE = lltype.nullptr(OBJECTSTORE)
- def customtrace(gc, obj, callback, arg):
- #debug_print('in customtrace w/obj', obj)
- length = (obj + offset_of_length).signed[0]
- step = (obj + offset_of_step).signed[0]
- storage = (obj + offset_of_storage).address[0]
- #debug_print('tracing', length, 'objects in ndarray.storage')
- i = 0
- while i < length:
- gc._trace_callback(callback, arg, storage)
- storage += step
- i += 1
- lambda_customtrace = lambda: customtrace
- def _setup():
- rgc.register_custom_trace_hook(OBJECTSTORE, lambda_customtrace)
- @jit.dont_look_inside
- def _create_objectstore(storage, length, elsize):
- gcstruct = lltype.malloc(OBJECTSTORE)
- # JIT does not support cast_ptr_to_adr
- gcstruct.storage = llmemory.cast_ptr_to_adr(storage)
- #print 'create gcstruct',gcstruct,'with storage',storage,'as',gcstruct.storage
- gcstruct.length = length
- gcstruct.step = elsize
- return gcstruct
- class ConcreteArrayNotOwning(BaseConcreteArray):
- def __init__(self, shape, dtype, order, strides, backstrides, storage, start=0):
- make_sure_not_resized(shape)
- make_sure_not_resized(strides)
- make_sure_not_resized(backstrides)
- self.shape = shape
- # already tested for overflow in from_shape_and_storage
- self.size = support.product(shape) * dtype.elsize
- if order not in (NPY.CORDER, NPY.FORTRANORDER):
- raise oefmt(dtype.itemtype.space.w_ValueError, "ConcreteArrayNotOwning but order is not 0,1 rather %d", order)
- self.order = order
- self.dtype = dtype
- self.strides = strides
- self.backstrides = backstrides
- self.storage = storage
- self.start = start
- self.gcstruct = V_OBJECTSTORE
- def fill(self, space, box):
- self.dtype.itemtype.fill(
- self.storage, self.dtype.elsize, self.dtype.is_native(),
- box, 0, self.size, 0, self.gcstruct)
- def set_shape(self, space, orig_array, new_shape):
- if len(new_shape) > NPY.MAXDIMS:
- raise oefmt(space.w_ValueError,
- "sequence too large; cannot be greater than %d", NPY.MAXDIMS)
- try:
- ovfcheck(support.product_check(new_shape) * self.dtype.elsize)
- except OverflowError as e:
- raise oefmt(space.w_ValueError, "array is too big.")
- strides, backstrides = calc_strides(new_shape, self.dtype,
- self.order)
- return SliceArray(self.start, strides, backstrides, new_shape, self,
- orig_array)
- def set_dtype(self, space, dtype):
- # size/shape/strides shouldn't change
- assert dtype.elsize == self.dtype.elsize
- self.dtype = dtype
- def argsort(self, space, w_axis):
- from .selection import argsort_array
- return argsort_array(self, space, w_axis)
- def sort(self, space, w_axis, w_order):
- from .selection import sort_array
- return sort_array(self, space, w_axis, w_order)
- def base(self):
- return None
- class ConcreteArray(ConcreteArrayNotOwning):
- def __init__(self, shape, dtype, order, strides, backstrides,
- storage=lltype.nullptr(RAW_STORAGE), zero=True):
- gcstruct = V_OBJECTSTORE
- flags = NPY.ARRAY_ALIGNED | NPY.ARRAY_WRITEABLE
- try:
- length = support.product_check(shape)
- self.size = ovfcheck(length * dtype.elsize)
- except OverflowError:
- raise oefmt(dtype.itemtype.space.w_ValueError, "array is too big.")
- if storage == lltype.nullptr(RAW_STORAGE):
- if dtype.num == NPY.OBJECT:
- storage = dtype.itemtype.malloc(length * dtype.elsize, zero=True)
- gcstruct = _create_objectstore(storage, length, dtype.elsize)
- else:
- storage = dtype.itemtype.malloc(length * dtype.elsize, zero=zero)
- flags |= NPY.ARRAY_OWNDATA
- start = calc_start(shape, strides)
- ConcreteArrayNotOwning.__init__(self, shape, dtype, order, strides, backstrides,
- storage, start=start)
- self.gcstruct = gcstruct
- if is_c_contiguous(self):
- flags |= NPY.ARRAY_C_CONTIGUOUS
- if is_f_contiguous(self):
- flags |= NPY.ARRAY_F_CONTIGUOUS
- self.flags = flags
- def __del__(self):
- if self.gcstruct:
- self.gcstruct.length = 0
- free_raw_storage(self.storage, track_allocation=False)
- class ConcreteArrayWithBase(ConcreteArrayNotOwning):
- def __init__(self, shape, dtype, order, strides, backstrides, storage,
- orig_base, start=0):
- ConcreteArrayNotOwning.__init__(self, shape, dtype, order,
- strides, backstrides, storage, start)
- self.orig_base = orig_base
- if isinstance(orig_base, W_NumpyObject):
- flags = orig_base.get_flags() & NPY.ARRAY_ALIGNED
- flags |= orig_base.get_flags() & NPY.ARRAY_WRITEABLE
- else:
- flags = 0
- if is_c_contiguous(self):
- flags |= NPY.ARRAY_C_CONTIGUOUS
- if is_f_contiguous(self):
- flags |= NPY.ARRAY_F_CONTIGUOUS
- self.flags = flags
- def base(self):
- return self.orig_base
- class ConcreteNonWritableArrayWithBase(ConcreteArrayWithBase):
- def __init__(self, shape, dtype, order, strides, backstrides, storage,
- orig_base, start=0):
- ConcreteArrayWithBase.__init__(self, shape, dtype, order, strides,
- backstrides, storage, orig_base, start)
- self.flags &= ~ NPY.ARRAY_WRITEABLE
- def descr_setitem(self, space, orig_array, w_index, w_value):
- raise oefmt(space.w_ValueError, "assignment destination is read-only")
- class NonWritableArray(ConcreteArray):
- def __init__(self, shape, dtype, order, strides, backstrides,
- storage=lltype.nullptr(RAW_STORAGE), zero=True):
- ConcreteArray.__init__(self, shape, dtype, order, strides, backstrides,
- storage, zero)
- self.flags &= ~ NPY.ARRAY_WRITEABLE
- def descr_setitem(self, space, orig_array, w_index, w_value):
- raise oefmt(space.w_ValueError, "assignment destination is read-only")
- class SliceArray(BaseConcreteArray):
- def __init__(self, start, strides, backstrides, shape, parent, orig_arr,
- dtype=None):
- 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.gcstruct = parent.gcstruct
- if parent.order not in (NPY.CORDER, NPY.FORTRANORDER):
- raise oefmt(dtype.itemtype.space.w_ValueError, "SliceArray but parent order is not 0,1 rather %d", parent.order)
- self.order = parent.order
- self.dtype = dtype
- try:
- self.size = ovfcheck(support.product_check(shape) * self.dtype.elsize)
- except OverflowError:
- raise oefmt(dtype.itemtype.space.w_ValueError, "array is too big.")
- self.start = start
- self.orig_arr = orig_arr
- flags = parent.flags & NPY.ARRAY_ALIGNED
- flags |= parent.flags & NPY.ARRAY_WRITEABLE
- if is_c_contiguous(self):
- flags |= NPY.ARRAY_C_CONTIGUOUS
- if is_f_contiguous(self):
- flags |= NPY.ARRAY_F_CONTIGUOUS
- self.flags = flags
- def base(self):
- return self.orig_arr
- def fill(self, space, box):
- loop.fill(self, box.convert_to(space, self.dtype))
- def set_shape(self, space, orig_array, new_shape):
- if len(new_shape) > NPY.MAXDIMS:
- raise oefmt(space.w_ValueError,
- "sequence too large; cannot be greater than %d", NPY.MAXDIMS)
- try:
- ovfcheck(support.product_check(new_shape) * self.dtype.elsize)
- except OverflowError as e:
- raise oefmt(space.w_ValueError, "array is too big.")
- if len(self.get_shape()) < 2 or self.size == 0:
- # TODO: this code could be refactored into calc_strides
- # but then calc_strides would have to accept a stepping factor
- strides = []
- backstrides = []
- dtype = self.dtype
- try:
- s = self.get_strides()[0] // dtype.elsize
- except IndexError:
- s = 1
- if self.order != NPY.FORTRANORDER:
- new_shape.reverse()
- for sh in new_shape:
- strides.append(s * dtype.elsize)
- backstrides.append(s * (sh - 1) * dtype.elsize)
- s *= max(1, sh)
- if self.order != NPY.FORTRANORDER:
- strides.reverse()
- backstrides.reverse()
- new_shape.reverse()
- return self.__class__(self.start, strides, backstrides, new_shape,
- self, orig_array)
- new_strides = calc_new_strides(new_shape, self.get_shape(),
- self.get_strides(),
- self.order)
- if new_strides is None or len(new_strides) != len(new_shape):
- raise oefmt(space.w_AttributeError,
- "incompatible shape for a non-contiguous array")
- new_backstrides = [0] * len(new_shape)
- for nd in range(len(new_shape)):
- new_backstrides[nd] = (new_shape[nd] - 1) * new_strides[nd]
- return self.__class__(self.start, new_strides, new_backstrides, new_shape,
- self, orig_array)
- def sort(self, space, w_axis, w_order):
- from .selection import sort_array
- return sort_array(self, space, w_axis, w_order)
- class NonWritableSliceArray(SliceArray):
- def __init__(self, start, strides, backstrides, shape, parent, orig_arr,
- dtype=None):
- SliceArray.__init__(self, start, strides, backstrides, shape, parent,
- orig_arr, dtype)
- self.flags &= ~NPY.ARRAY_WRITEABLE
- def descr_setitem(self, space, orig_array, w_index, w_value):
- raise oefmt(space.w_ValueError, "assignment destination is read-only")
- class VoidBoxStorage(BaseConcreteArray):
- def __init__(self, size, dtype):
- self.storage = alloc_raw_storage(size)
- self.gcstruct = V_OBJECTSTORE
- self.dtype = dtype
- self.size = size
- self.flags = (NPY.ARRAY_C_CONTIGUOUS | NPY.ARRAY_F_CONTIGUOUS |
- NPY.ARRAY_WRITEABLE | NPY.ARRAY_ALIGNED)
- def __del__(self):
- free_raw_storage(self.storage)
- class ArrayBuffer(Buffer):
- _immutable_ = True
- def __init__(self, impl, readonly):
- self.impl = impl
- self.readonly = readonly
- def getitem(self, index):
- return raw_storage_getitem(lltype.Char, self.impl.storage,
- index + self.impl.start)
- def setitem(self, index, v):
- raw_storage_setitem(self.impl.storage, index + self.impl.start,
- rffi.cast(lltype.Char, v))
- def getlength(self):
- return self.impl.size - self.impl.start
- def get_raw_address(self):
- from rpython.rtyper.lltypesystem import rffi
- return rffi.ptradd(self.impl.storage, self.impl.start)