def normalize_range(e, n):
    """
    Return the range tuple normalized for an ``n``-element object.

    The semantics of a range  is slightly different than that of a slice.
    In particular, a range is similar to a list in meaning (and on Py2 it was
    eagerly expanded into a list). Thus we do not allow the range to generate
    indices that would be invalid for an ``n``-array. Furthermore, we restrict
    the range to produce only positive or only negative indices. For example,
    ``range(2, -2, -1)`` expands into ``[2, 1, 0, -1]``, and it is confusing
    to treat the last "-1" as the last element in the list.

    :param e: a range object representing a selector
    :param n: number of elements in a sequence to which ``e`` is applied
    :returns: tuple ``(start, count, step)`` derived from ``e``, or None
        if the range is invalid.
    """
    if e.step > 0:
        count = max(0, (e.stop - e.start - 1) // e.step + 1)
    else:
        count = max(0, (e.start - e.stop - 1) // -e.step + 1)
    if count == 0:
        return 0, 0, e.step
    start = e.start
    finish = e.start + (count - 1) * e.step
    if start >= 0:
        if start >= n or finish < 0 or finish >= n:
            return None
    else:
        start += n
        finish += n
        if start < 0 or start >= n or finish < 0 or finish >= n:
            return None
    assert count >= 0
    return start, count, e.step
