def join_slices(*slices):
    """Join together contiguous slices by extending their start and/or end points.

    All slices must be increasing, i.e. start < stop.
    Identical slices will be removed.

    Args:
        *slices (iterable of slice): Slices to concatenate.

    Examples:
        >>> join_slices(slice(0, 2), slice(2, 4))
        slice(0, 4, None)
        >>> join_slices(slice(0, 2), slice(2, 4), slice(-2, 0))
        slice(-2, 4, None)

    Raises:
        ValueError: If any of the given slices defines a step other than 1 or None.
        ValueError: If the slices are not contiguous.
        ValueError: If any of the slices are not increasing.

    """
    if not slices:
        raise ValueError("No slices were given.")
    for s in slices:
        if s.step not in (None, 1):
            raise ValueError("Slices may not define a step other than 1 or None.")
        if s.stop < s.start:
            raise ValueError("Slices must be increasing.")

    if len(slices) == 1:
        return slices[0]

    # Sort unique slices by their start.
    slices = sorted(
        (
            slice(*elements)
            for elements in set((s.start, s.stop, s.step) for s in slices)
        ),
        key=lambda s: s.start,
    )

    # Ensure they are contiguous.
    for s1, s2 in zip(slices[:-1], slices[1:]):
        if s1.stop != s2.start:
            raise ValueError("All slices must be contiguous.")

    return slice(slices[0].start, slices[-1].stop)