def putmask(a: ndarray, mask: ndarray, values: ndarray) -> None:
    """
    putmask(a, mask, values)
    Changes elements of an array based on conditional and input values.
    Sets ``a.flat[n] = values[n]`` for each n where ``mask.flat[n]==True``.
    If `values` is not the same size as `a` and `mask` then it will repeat.
    This gives behavior different from ``a[mask] = values``.

    Parameters
    ----------
    a : ndarray
        Target array.
    mask : array_like
        Boolean mask array. It has to be the same shape as `a`.
    values : array_like
        Values to put into `a` where `mask` is True. If `values` is smaller
        than `a` it will be repeated.

    See Also
    --------
    numpy.putmask

    Availability
    ------------
    Multiple GPUs, Multiple CPUs
    """
    if not a.shape == mask.shape:
        raise ValueError("mask and data must be the same size")

    check_writeable(a)

    mask = _warn_and_convert(mask, np.dtype(bool))

    if a.dtype != values.dtype:
        values = _warn_and_convert(values, a.dtype)

    try:
        np.broadcast_shapes(values.shape, a.shape)
    except ValueError:
        values = values._wrap(a.size)
        values = values.reshape(a.shape)

    a._thunk.putmask(mask._thunk, values._thunk)

    putmask(a, mask, values)
    Changes elements of an array based on conditional and input values.
    Sets ``a.flat[n] = values[n]`` for each n where ``mask.flat[n]==True``.
    If `values` is not the same size as `a` and `mask` then it will repeat.
    This gives behavior different from ``a[mask] = values``.

    Parameters
    ----------
    a : ndarray
        Target array.
    mask : array_like
        Boolean mask array. It has to be the same shape as `a`.
    values : array_like
        Values to put into `a` where `mask` is True. If `values` is smaller
        than `a` it will be repeated.

    See Also
    --------
    numpy.putmask

    Availability
    ------------
    Multiple GPUs, Multiple CPUs
    
cupynumeric/_module/indexing.py