def take_along_axis(a: ndarray, indices: ndarray, axis: int | None) -> ndarray:
    """
    Take values from the input 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 look up values in 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
    ----------
    arr : ndarray (Ni..., M, Nk...)
        Source array
    indices : ndarray (Ni..., J, Nk...)
        Indices to take along each 1d slice of `arr`. This must match the
        dimension of arr, but dimensions Ni and Nj only need to broadcast
        against `arr`.
    axis : int
        The axis to take 1d slices along. If axis is None, the input array is
        treated as if it had first been flattened to 1d, for consistency with
        :func:`cupynumeric.sort` and :func:`cupynumeric.argsort`.

    Returns
    -------
    out: ndarray (Ni..., J, Nk...)
        The indexed result. It is going to be a view to `arr` for most cases,
        except the case when `axis=Null` and `arr.ndim>1`.

    See Also
    --------
    numpy.take_along_axis

    Availability
    --------
    Multiple GPUs, Multiple CPUs
    """
    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:
            a = a.ravel()
    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"
        )
    return a[
        _fill_fancy_index_for_along_axis_routines(
            a.shape, computed_axis, indices
        )
    ]

    Take values from the input 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 look up values in 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
    ----------
    arr : ndarray (Ni..., M, Nk...)
        Source array
    indices : ndarray (Ni..., J, Nk...)
        Indices to take along each 1d slice of `arr`. This must match the
        dimension of arr, but dimensions Ni and Nj only need to broadcast
        against `arr`.
    axis : int
        The axis to take 1d slices along. If axis is None, the input array is
        treated as if it had first been flattened to 1d, for consistency with
        :func:`cupynumeric.sort` and :func:`cupynumeric.argsort`.

    Returns
    -------
    out: ndarray (Ni..., J, Nk...)
        The indexed result. It is going to be a view to `arr` for most cases,
        except the case when `axis=Null` and `arr.ndim>1`.

    See Also
    --------
    numpy.take_along_axis

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