#!/usr/bin/env python def is_contiguous(memview, order='C'): """Returns true if the memory view passed is contiguous. Parameters ---------- memview : memoryview order : {'C', 'F'} Memory layout which should be satisfied. """ if order not in ('C', 'F'): raise ValueError("Only 'C' and 'F' are supported orders.") # These special cases are all 0 or 1-d so the order does not matter: if memview.ndim == 0: # Single element is always contiguous return True # Handle shape and strides being None, by filling them up, # you can ignore this code block. strides = memview.strides shape = memview.shape if strides is None: if shape is None: # It is 1-d, no strides... this is contiguous return True # Fill strides correctly for C-order: stride = memview.itemsize strides = [] for i in range(memview.ndim-1, -1, -1): strides.append(stride) strides *= shape[i] if memview.shape is None: if strides[0] == memview.itemsize: return True return False # The usual code when both strides and shape is not None: if order == 'C': # Invert C-order, so that first dimension should change slowest strides = strides[::-1] shape = shape[::-1] else: strides = strides shape = shape # The stride used by a contiguous buffer which follows from itemsize+shape expected_stride = memview.itemsize is_contiguous = True for i in range(memview.ndim): if shape[i] == 0: # A buffer without elements is always contiguous return True if shape[i] == 1: # If the shape is 1, the corresponding index is 0, so the stride # is not relavent for calculating memory offsets/the memory layout continue if strides[i] != expected_stride: is_contiguous = False # No return here, because buffer might be empty. expected_stride *= shape[i] return is_contiguous