U
    #c4D                     @   sr  d Z ddddddgZddlZdd	lmZmZmZmZm	Z	 dd
l
mZmZ zddlZW n ek
rl   dZY nX edkrdd ZeZeZeZddlmZ eZn*ddlm  mZ e Z[ejZdd Zdd ZddddddgZdd ZG dd deZ G dd de Z!i Z"d-ddZ#edk	rndd Z$d d! Z%e% Z&d"d# Z'd$d% Z(d&d' Z)d(d) Z*d*d Z+d.d+dZd,d ZdS )/a7  
============================
``ctypes`` Utility Functions
============================

See Also
--------
load_library : Load a C library.
ndpointer : Array restype/argtype with verification.
as_ctypes : Create a ctypes array from an ndarray.
as_array : Create an ndarray from a ctypes array.

References
----------
.. [1] "SciPy Cookbook: ctypes", https://scipy-cookbook.readthedocs.io/items/Ctypes.html

Examples
--------
Load the C library:

>>> _lib = np.ctypeslib.load_library('libmystuff', '.')     #doctest: +SKIP

Our result type, an ndarray that must be of type double, be 1-dimensional
and is C-contiguous in memory:

>>> array_1d_double = np.ctypeslib.ndpointer(
...                          dtype=np.double,
...                          ndim=1, flags='CONTIGUOUS')    #doctest: +SKIP

Our C-function typically takes an array and updates its values
in-place.  For example::

    void foo_func(double* x, int length)
    {
        int i;
        for (i = 0; i < length; i++) {
            x[i] = i*i;
        }
    }

We wrap it using:

>>> _lib.foo_func.restype = None                      #doctest: +SKIP
>>> _lib.foo_func.argtypes = [array_1d_double, c_int] #doctest: +SKIP

Then, we're ready to call ``foo_func``:

>>> out = np.empty(15, dtype=np.double)
>>> _lib.foo_func(out, len(out))                #doctest: +SKIP

load_library	ndpointerc_intp	as_ctypesas_arrayas_ctypes_type    N)integerndarraydtypeasarray
frombuffer)	_flagdictflagsobjc                  O   s   t ddS )z
        Dummy object that raises an ImportError if ctypes is not available.

        Raises
        ------
        ImportError
            If ctypes is not available.

        zctypes is not available.N)ImportError)argskwds r   3/tmp/pip-unpacked-wheel-b2rbor69/numpy/ctypeslib.py_dummyC   s    
r   )intpc              	   C   s  t jdk r ddl}|jddd t| } t|}tj| d }|sddlm	} | }| | g}|d	d
}||ks|
d| |  n| g}tj|}tj|stj|}n|}|D ]H}	tj||	}
tj|
rzt j|
 W   S  tk
r    Y qX qtddS )a
  
        It is possible to load a library using

        >>> lib = ctypes.cdll[<full_path_name>] # doctest: +SKIP

        But there are cross-platform considerations, such as library file extensions,
        plus the fact Windows will just load the first library it finds with that name.
        NumPy supplies the load_library function as a convenience.

        .. versionchanged:: 1.20.0
            Allow libname and loader_path to take any
            :term:`python:path-like object`.

        Parameters
        ----------
        libname : path-like
            Name of the library, which can have 'lib' as a prefix,
            but without an extension.
        loader_path : path-like
            Where the library can be found.

        Returns
        -------
        ctypes.cdll[libpath] : library object
           A ctypes library object

        Raises
        ------
        OSError
            If there is no library with the expected extension, or the
            library is defective and cannot be loaded.
        z1.0.1r   NzAAll features of ctypes interface may not work with ctypes < 1.0.1   )
stacklevel   )get_shared_lib_extensionT)Zis_python_extzno file with expected extension)ctypes__version__warningswarnosfsdecodepathsplitextZnumpy.distutils.misc_utilr   insertabspathisdirdirnamejoinexistscdllOSError)ZlibnameZloader_pathr   extr   Zso_extZlibname_extZso_ext2ZlibdirlnZlibpathr   r   r   r   Z   s8    !





c                 C   s   d}| D ]}|t | 7 }q|S Nr   )r   )Zflaglistnumvalr   r   r   _num_fromflags   s    r/   ZC_CONTIGUOUSZF_CONTIGUOUSZALIGNEDZ	WRITEABLEZOWNDATAZWRITEBACKIFCOPYc                 C   s,   g }t D ]}t| }| |@ r|| q|S N)
_flagnamesr   append)r-   reskeyvaluer   r   r   _flags_fromnum   s    r6   c                   @   s   e Zd Zedd ZdS )_ndptrc                 C   s   t |tstd| jd k	r6|j| jkr6td| j | jd k	rZ|j| jkrZtd| j | jd k	r|j| jkrtdt	| j | j
d k	r|jj| j
@ | j
krtdt| j
 |jS )Nzargument must be an ndarrayzarray must have data type %szarray must have %d dimension(s)zarray must have shape %szarray must have flags %s)
isinstancer	   	TypeError_dtype_r
   _ndim_ndim_shape_shapestr_flags_flagsr-   r6   r   )clsobjr   r   r   
from_param   s*    







z_ndptr.from_paramN)__name__
__module____qualname__classmethodrD   r   r   r   r   r7      s   r7   c                   @   s$   e Zd ZdZdd Zedd ZdS )_concrete_ndptrz
    Like _ndptr, but with `_shape_` and `_dtype_` specified.

    Notably, this means the pointer has enough information to reconstruct
    the array, which is not generally true.
    c                 C   s   | j S )z
        This method is called when this class is used as the .restype
        attribute for a shared-library function, to automatically wrap the
        pointer into an array.
        )contents)selfr   r   r   _check_retval_   s    z_concrete_ndptr._check_retval_c                 C   sD   t | j| jf}tj|j }t| t|j}t	||dj
ddS )z
        Get an ndarray viewing the data pointed to by this pointer.

        This mirrors the `contents` attribute of a normal ctypes pointer
        r
   r   )Zaxis)_dtyper:   r=   r   c_charitemsizecastPOINTERrJ   r   Zsqueeze)rK   Z
full_dtypeZ
full_ctypebufferr   r   r   rJ      s    z_concrete_ndptr.contentsN)rE   rF   rG   __doc__rL   propertyrJ   r   r   r   r   rI      s   rI   c           
   
   C   s  | dk	rt | } d}|dk	rt|tr2|d}n4t|ttfrN|}t|}nt|trf|j}t|}|dkrzdd |D }W n, t	k
r } zt
d|W 5 d}~X Y nX t|}|dk	rzt|}W n t
k
r   |f}Y nX | |||f}z
t| W S  tk
r   Y nX | dkr$d}n | jdk	r>tt| }n| j}|dk	rZ|d| 7 }|dk	r|dd	d
d |D  7 }|dk	r|dd| 7 }| dk	r|dk	rt}nt}td| |f| |||d}	|	t|< |	S )aF  
    Array-checking restype/argtypes.

    An ndpointer instance is used to describe an ndarray in restypes
    and argtypes specifications.  This approach is more flexible than
    using, for example, ``POINTER(c_double)``, since several restrictions
    can be specified, which are verified upon calling the ctypes function.
    These include data type, number of dimensions, shape and flags.  If a
    given array does not satisfy the specified restrictions,
    a ``TypeError`` is raised.

    Parameters
    ----------
    dtype : data-type, optional
        Array data-type.
    ndim : int, optional
        Number of array dimensions.
    shape : tuple of ints, optional
        Array shape.
    flags : str or tuple of str
        Array flags; may be one or more of:

          - C_CONTIGUOUS / C / CONTIGUOUS
          - F_CONTIGUOUS / F / FORTRAN
          - OWNDATA / O
          - WRITEABLE / W
          - ALIGNED / A
          - WRITEBACKIFCOPY / X

    Returns
    -------
    klass : ndpointer type object
        A type object, which is an ``_ndtpr`` instance containing
        dtype, ndim, shape and flags information.

    Raises
    ------
    TypeError
        If a given array does not satisfy the specified restrictions.

    Examples
    --------
    >>> clib.somefunc.argtypes = [np.ctypeslib.ndpointer(dtype=np.float64,
    ...                                                  ndim=1,
    ...                                                  flags='C_CONTIGUOUS')]
    ... #doctest: +SKIP
    >>> clib.somefunc(np.array([1, 2, 3], dtype=np.float64))
    ... #doctest: +SKIP

    N,c                 S   s   g | ]}|   qS r   )stripupper.0xr   r   r   
<listcomp>0  s     zndpointer.<locals>.<listcomp>zinvalid flags specificationanyz_%dd_r[   c                 s   s   | ]}t |V  qd S r0   )r?   rY   r   r   r   	<genexpr>N  s     zndpointer.<locals>.<genexpr>zndpointer_%s)r:   r=   r;   r@   )rN   r8   r?   splitintr   r6   r   r-   	Exceptionr9   r/   tuple_pointer_type_cacheKeyErrornamesidr&   rI   r7   type)
r
   r<   r>   rA   r-   e	cache_keynamebaseklassr   r   r   r      sf    5







c                 C   s&   |ddd D ]}||  } d| _ q| S )z7 Create an ndarray of the given element type and shape N)rF   )Zelement_typer>   Zdimr   r   r   _ctype_ndarraya  s    ro   c                  C   sJ   t } | j| j| j| j| j| j| j| j| j	| j
| j| j| jg}dd |D S )zX
        Return a dictionary mapping native endian scalar dtype to ctypes types
        c                 S   s   i | ]}t ||qS r   )rN   )rZ   ctyper   r   r   
<dictcomp>u  s      z(_get_scalar_type_map.<locals>.<dictcomp>)r   c_bytec_shortc_intc_long
c_longlongc_ubytec_ushortc_uintc_ulongc_ulonglongc_floatc_doublec_bool)ctZsimple_typesr   r   r   _get_scalar_type_mapj  s              r   c              
   C   s   |  d d}|  d}zt| }W n2 tk
rX } ztd| d W 5 d }~X Y nX |jdkrl|j}n|jdkr||j}|S )NS=z Converting {!r} to a ctypes type><)Znewbyteorder_scalar_type_mapre   NotImplementedErrorformat	byteorder__ctype_be____ctype_le__)r
   Zdtype_with_endianZdtype_nativerp   ri   r   r   r   _ctype_from_dtype_scalar{  s    


r   c                 C   s   | j \}}t|}t||S r0   )subdtype_ctype_from_dtypero   )r
   Zelement_dtyper>   rp   r   r   r   _ctype_from_dtype_subarray  s    
r   c           
      C   s  g }| j D ].}| j| d d \}}|||t|f q
t|dd d}t|dkrtdd |D rd}g }|D ](\}}}|||f t|t	|}qt| j
|kr|d	tj| j
 f td
tjft|dd dS d}g }|D ]^\}}}|| }	|	dk rtd|	dkr&|d	tj|	 f |||f |t	| }q| j
| }	|	dkrl|d	tj|	 f tdtjft|dd dS d S )Nr   c                 S   s   | d S r,   r   )fr   r   r   <lambda>      z._ctype_from_dtype_structured.<locals>.<lambda>)r4   r   c                 s   s   | ]\}}}|d kV  qdS )r   Nr   )rZ   offsetrk   rp   r   r   r   r_     s     z/_ctype_from_dtype_structured.<locals>.<genexpr>r    union)_fields_Z_pack_rF   zOverlapping fieldsstruct)rf   fieldsr2   r   sortedlenallmaxr   sizeofrP   rO   rh   Uniondictr   	Structure)
r
   Z
field_datark   Zfield_dtyper   sizer   rp   Zlast_offsetpaddingr   r   r   _ctype_from_dtype_structured  sH    





r   c                 C   s0   | j d k	rt| S | jd k	r$t| S t| S d S r0   )r   r   r   r   r   rM   r   r   r   r     s
    

r   c                 C   s   t t| S )a  
        Convert a dtype into a ctypes type.

        Parameters
        ----------
        dtype : dtype
            The dtype to convert

        Returns
        -------
        ctype
            A ctype scalar, union, array, or struct

        Raises
        ------
        NotImplementedError
            If the conversion is not possible

        Notes
        -----
        This function does not losslessly round-trip in either direction.

        ``np.dtype(as_ctypes_type(dt))`` will:

         - insert padding fields
         - reorder fields to be sorted by offset
         - discard field titles

        ``as_ctypes_type(np.dtype(ctype))`` will:

         - discard the class names of `ctypes.Structure`\ s and
           `ctypes.Union`\ s
         - convert single-element `ctypes.Union`\ s into single-element
           `ctypes.Structure`\ s
         - insert padding fields

        )r   rN   rM   r   r   r   r     s    &c                 C   sD   t | tjr<|dkrtdtt| j|}t| |j} t	| S )a"  
        Create a numpy array from a ctypes array or POINTER.

        The numpy array shares the memory with the ctypes object.

        The shape parameter must be given if converting from a ctypes POINTER.
        The shape parameter is ignored if converting from a ctypes array
        Nz=as_array() requires a shape argument when called on a pointer)
r8   r   _Pointerr9   rR   ro   _type_rQ   rJ   r   )rC   r>   Z
p_arr_typer   r   r   r     s    	c                 C   sp   | j }|d rtd|d dkr*td|d \}}|rBtdt|d }t||d	 }||}| |_|S )
zCreate and return a ctypes object from a numpy array.  Actually
        anything that exposes the __array_interface__ is accepted.strideszstrided arrays not supportedversion   z,only __array_interface__ version 3 supporteddatazreadonly arrays unsupportedZtypestrr>   )Z__array_interface__r9   r   ro   from_addressZ__keep)rC   ZaiaddrreadonlyZctype_scalarZresult_typeresultr   r   r   r     s    
)NNNN)N),rT   __all__r   Znumpyr   r	   r
   rN   r   r   Znumpy.core.multiarrayr   r   r   r   r   r   r   r   r   r   objectZ_ndptr_baseZnumpy.core._internalcore	_internalZnicZ_getintp_ctypec_void_pr/   r1   r6   r7   rI   rd   r   ro   r   r   r   r   r   r   r   r   r   r   r   <module>   sV   3

L 	
u
	6	)
