# sdl2.ext.array - Tools for Working with ctypes Arrays

This module provides a number of utilites for accessing data in `ctypes` arrays and converting `ctypes` arrays into common Python formats.

Warning

These functions are primarily meant for internal use in PySDL2, and should be treated as experimental.

## Providing read-write access for sequential data

Two classes allow you to access sequential data in different ways. The `CTypesView` provides byte-wise access to iterable objects and allows you to convert the object representation to matching byte-widths for `ctypes` or other modules.

Depending on the the underlying object and the chosen size of each particular item of the object, the `CTypesView` allows you to operate directly on different representations of the object’s contents.

    >>> text = bytearray("Hello, I am a simple ASCII string!")
    >>> ctview = CTypesView(text, itemsize=1)
    >>> ctview.view[0] = 0x61
    >>> print(text)
    aello, I am a simple ASCII string!"
    >>> ctview.to_uint16()[3] = 0x6554
    >>> print(text)
    aello,Te am a simple ASCII string!"

The snippet above provides a single-byte sized view on a `bytearray()` object. Afterwards, the first item of the view is changed, which causes a change on the `bytearray()`, on the first item as well, since both, the `CTypesView` and the `bytearray()` provide a byte-wise access to the contents.

By using `CTypesView.to_uint16()`, we change the access representation to a 2-byte unsigned integer `ctypes` pointer and change the fourth 2-byte value, I to something else.

    >>> text = bytearray("Hello, I am a simple ASCII string!")
    >>> ctview = CTypesView(text, itemsize=2)
    >>> ctview.view[0] = 0x61
    >>> print(text)
    aello, I am a simple ASCII string!"
    >>> ctview.to_uint16()[3] = 0x6554
    >>> print(text)    aello,Te am a simple ASCII string!"

If the encapsuled object does not provide a (writable) `buffer()` interface, but is iterable, the `CTypesView` will create an internal copy of the object data using Python’s `array` module and perform all operations on that copy.

    >>> mylist = [18, 52, 86, 120, 154, 188, 222, 240]
    >>> ctview = CTypesView(mylist, itemsize=1, docopy=True)
    >>> print(ctview.object)
    array('B', [18, 52, 86, 120, 154, 188, 222, 240])
    >>> ctview.view[3] = 0xFF
    >>> print(mylist)
    [18, 52, 86, 120, 154, 188, 222, 240]
    >>> print(ctview.object)
    array('B', [18, 52, 86, 255, 154, 188, 222, 240])

As for directly accessible objects, you can define your own itemsize to be used. If the iterable does not provide a direct byte access to their contents, this won’t have any effect except for resizing the item widths.

    >>> mylist = [18, 52, 86, 120, 154, 188, 222, 240]
    >>> ctview = CTypesView(mylist, itemsize=4, docopy=True)
    >>> print(ctview.object)
    array('I', [18L, 52L, 86L, 120L, 154L, 188L, 222L, 240L])

## Accessing data over multiple dimensions

The second class, `MemoryView` provides an interface to access data over multiple dimensions. You can layout and access a simple byte stream over e.g. two or more axes, providing a greater flexibility for functional operations and complex data.

Let’s assume, we are reading image data from a file stream into some buffer object and want to access and manipulate the image data. Images feature two axes, one being the width, the other being the height, defining a rectangular graphics area.

When we read all data from the file, we have an one-dimensional view of the image graphics. The `MemoryView` allows us to define a two-dimensional view over the image graphics, so that we can operate on both, rows and columns of the image.

    >>> imagedata = bytearray("some 1-byte graphics data")
    >>> view = MemoryView(imagedata, 1, (5, 5))
    >>> print(view)
    [[s, o, m, e,  ], [1, -, b, y, t], [e,  , g, r, a], [p, h, i, c, s], [ , d, a, t, a]]
    >>> for row in view:
    ...     print(row)
    ...
    [s, o, m, e,  ]
    [1, -, b, y, t]
    [e,  , g, r, a]
    [p, h, i, c, s]
    [ , d, a, t, a]
    >>> for row in view:
    ...    row[1] = "X"
    ...    print(row)
    ...
    [s, X, m, e,  ]
    [1, X, b, y, t]
    [e, X, g, r, a]
    [p, X, i, c, s]
    [ , X, a, t, a]
    >>> print(imagedata)
    sXme 1XbyteXgrapXics Xata

On accessing a particular dimension of a `MemoryView`, a new `MemoryView` is created, if it does not access a single element.

    >>> firstrow = view[0]
    >>> type(firstrow)
    <class 'sdl2.ext.array.MemoryView'>
    >>> type(firstrow[0])
    <type 'bytearray'>

A `MemoryView` features, similar to Python’s builtin `memoryview`, dimensions and strides, accessible via the `MemoryView.ndim` and `MemoryView.strides` attributes.

    >>> view.ndim
    2
    >>> view.strides
    (5, 5)

The `MemoryView.strides`, which have to be passed on creating a new `MemoryView`, define the layout of the data over different dimensions. In the example above, we created a 5x5 two-dimensional view to the image graphics.

    >>> twobytes = MemoryView(imagedata, 2, (5, 1))
    >>> print(twobytes)
    [[sX, me,  1, Xb, yt], [eX, gr, ap, Xi, cs]]

## Array API

class sdl2.ext.array.CTypesView(obj, itemsize=1, docopy=False, objsize=None)

  A proxy for accessing byte-wise `ctypes` data types.

  This class provides read-write access for arbitrary `ctypes` objects that are iterable. In case the object does not provide a `buffer()` interface for direct access, a `CTypesView` can copy the object’s contents into an internal buffer from which data can be retrieved.

  Depending on the item type stored in the iterable object, you might need to manually specify the object’s item size (in bytes). Additionally, you may need to manually specify the number of items in the iterable if it does not properly return its length using the `len` function.

  For certain types, such as the bytearray, the original object must not be reassigned after being encapsuled and used in ctypes bindings if the contents are not copied.

  Parameters:

    - obj – An arbitrary iterable `ctypes` object to access.

    - itemsize (int, optional) – The size (in bytes) of each item of the iterable object. Defaults to `1`.

    - docopy (bool, optional) – If True, the view will be created for a copy of the object and will not modify the original `ctypes` instance. Defalts to False (original object will be modified).

    - objsize (int, optional) – The number of items in the iterable object. If not specified, the number of items will try to be inferred automatically. Defaults to `None` (automatic inferrence).

  to_bytes()

    Casts the object to an array of bytes.

    If the view was created with `docopy = False` (the default), the returned object provides direct read-write access to the object data. Otherwise, the returned object will only modify a copy of the data.

    Returns:

      A pointer to a `ctypes.c_uint8` array.

    Return type:

      `ctypes._Pointer`

  to_uint16()

    Casts the object to an array of 16-bit unsigned ints.

    If the view was created with `docopy = False` (the default), the returned object provides direct read-write access to the object data. Otherwise, the returned object will only modify a copy of the data.

    Returns:

      A pointer to a `ctypes.c_uint16` array.

    Return type:

      `ctypes._Pointer`

  to_uint32()

    Casts the object to an array of 32-bit unsigned ints.

    If the view was created with `docopy = False` (the default), the returned object provides direct read-write access to the object data. Otherwise, the returned object will only modify a copy of the data.

    Returns:

      A pointer to a `ctypes.c_uint32` array.

    Return type:

      `ctypes._Pointer`

  to_uint64()

    Casts the object to an array of 64-bit unsigned ints.

    If the view was created with `docopy = False` (the default), the returned object provides direct read-write access to the object data. Otherwise, the returned object will only modify a copy of the data.

    Returns:

      A pointer to a `ctypes.c_uint64` array.

    Return type:

      `ctypes._Pointer`

  property bytesize

    The size (in bytes) of the underlying object.

    Type:

      int

  property view

    Provides a read/write-aware `ctypes` view of the encapsuled object.

  property is_shared

    Whether any modifications to the view will also modify the underlying object.

    Type:

      bool

  property object

    The underlying object.

sdl2.ext.array.to_ctypes(dataseq, dtype, mcount=0)

  Converts an arbitrary sequence to a `ctypes` array of a given type.

  Parameters:

    - dataseq – A sequence to convert to a `ctypes` array.

    - dtype (class) – The `ctypes` data type to use for the array (e.g. `ctypes.c_uint8`).

    - mcount (int, optional) – The number of elements in `dataseq`. If not specified, this will be inferred automatically.

  Returns:

    A tuple in the form `(valset, count)`, where `valset` is the converted `ctypes` array and `count` is the number of elements in the array.

  Return type:

    tuple

  Raises:

    TypeError – if any elements in the passed sequence do not match the specified type.

sdl2.ext.array.to_list(dataseq)

  Converts a `ctypes` array to a list.

sdl2.ext.array.to_tuple(dataseq)

  Converts a `ctypes` array to a tuple.

sdl2.ext.array.create_array(obj, itemsize)

  Creates an `array.array` copy of a given object.

  Parameters:

    - obj – The object from which the array will be created.

    - itemsize – The size (in bytes) of each item in the given object.

  Returns:

    The array created from the object.

  Return type:

    `array.array`

class sdl2.ext.array.MemoryView(source, itemsize, strides, getfunc=None, setfunc=None, srcsize=None)

  A class that provides read-write access to indexable `ctypes` objects.

  Note

  `MemoryView` makes heavy use of recursion for multi-dimensional access, making it slow for many use-cases. For better performance, the `numpy` library can be used for fast access to many array-like data types, but it may support fewer types of arbitrary objects than the `MemoryView` class.

  Parameters:

    - source – An arbitrary indexable `ctypes` object to access.

    - itemsize (int) – The size (in bytes) of each item of the indexable object.

    - strides (tuple) – The length of each dimension in the object (e.g. `(4, 3)` for a 4 x 3 2D array).

    - getfunc (function, optional) – Deprecated, do not use.

    - setfunc (function, optional) – Deprecated, do not use.

    - srcsize (int, optional) – The size (in bytes) of the input object. If `len(source)` returns the size of the object in bytes this will be inferred automatically, otherwise it must be manually specified.

  property size

    The size (in bytes) of the underlying source object.

    Type:

      int

  property strides

    The length of each dimension the MemoryView.

    Type:

      tuple

  property itemsize

    The size (in bytes) of a single item in the object.

    Type:

      int

  property ndim

    The number of dimensions of the MemoryView.

    Type:

      int

  property source

    The underlying data source.