def put_along_axis(
    a: ndarray, indices: ndarray, values: ndarray, axis: int | None
) -> None:
    """
    Put values into the destination array by matching 1d index and data slices.

    This iterates over matching 1d slices oriented along the specified axis in
    the index and data arrays, and uses the former to place values into the
    latter. These slices can be different lengths.

    Functions returning an index along an axis, like
    :func:`cupynumeric.argsort` and :func:`cupynumeric.argpartition`, produce
    suitable indices for this function.

    Parameters
    ----------
    a : ndarray (Ni..., M, Nk...)
        Destination array.
    indices : ndarray (Ni..., J, Nk...)
        Indices to change along each 1d slice of `arr`. This must match the
        dimension of arr, but dimensions in Ni and Nj may be 1 to broadcast
        against `arr`.
    values : array_like (Ni..., J, Nk...)
        values to insert at those indices. Its shape and dimension are
        broadcast to match that of `indices`.
    axis : int
        The axis to take 1d slices along. If axis is None, the destination
        array is treated as if a flattened 1d view had been created of it.
        `axis=None` case is currently supported only for 1D input arrays.

    Note
    ----
    Having duplicate entries in `indices` will result in undefined behavior
    since operation performs asynchronous update of the `arr` entries.

    See Also
    --------
    numpy.put_along_axis

    Availability
    --------
    Multiple GPUs, Multiple CPUs

    """

    if a.size == 0:
        return

    check_writeable(a)

    if not np.issubdtype(indices.dtype, np.integer):
        raise TypeError("`indices` must be an integer array")

    computed_axis = 0
    if axis is None:
        if indices.ndim != 1:
            raise ValueError("indices must be 1D if axis=None")
        if a.ndim > 1:
            # TODO call a=a.flat when flat is implemented
            raise ValueError("a.ndim>1 case is not supported when axis=None")
        if (indices.size == 0) or (values.size == 0):
            return
        if values.shape != indices.shape:
            values = values._wrap(indices.size)
    else:
        computed_axis = normalize_axis_index(axis, a.ndim)

    if a.ndim != indices.ndim:
        raise ValueError(
            "`indices` and `a` must have the same number of dimensions"
        )
    ind = _fill_fancy_index_for_along_axis_routines(
        a.shape, computed_axis, indices
    )
    a[ind] = values

    Put values into the destination array by matching 1d index and data slices.

    This iterates over matching 1d slices oriented along the specified axis in
    the index and data arrays, and uses the former to place values into the
    latter. These slices can be different lengths.

    Functions returning an index along an axis, like
    :func:`cupynumeric.argsort` and :func:`cupynumeric.argpartition`, produce
    suitable indices for this function.

    Parameters
    ----------
    a : ndarray (Ni..., M, Nk...)
        Destination array.
    indices : ndarray (Ni..., J, Nk...)
        Indices to change along each 1d slice of `arr`. This must match the
        dimension of arr, but dimensions in Ni and Nj may be 1 to broadcast
        against `arr`.
    values : array_like (Ni..., J, Nk...)
        values to insert at those indices. Its shape and dimension are
        broadcast to match that of `indices`.
    axis : int
        The axis to take 1d slices along. If axis is None, the destination
        array is treated as if a flattened 1d view had been created of it.
        `axis=None` case is currently supported only for 1D input arrays.

    Note
    ----
    Having duplicate entries in `indices` will result in undefined behavior
    since operation performs asynchronous update of the `arr` entries.

    See Also
    --------
    numpy.put_along_axis

    Availability
    --------
    Multiple GPUs, Multiple CPUs

    
cupynumeric/_module/indexing.py