gap method

Range<C> gap(
  1. Range<C> otherRange
)

Returns the maximal range lying between this range and {@code otherRange}, if such a range exists. The resulting range may be empty if the two ranges are adjacent but non-overlapping.

For example, the gap of {@code [1..5]} and {@code (7..10)} is {@code (5..7]}. The resulting range may be empty; for example, the gap between {@code [1..5)} {@code [5..7)} yields the empty range {@code [5..5)}.

The gap exists if and only if the two ranges are either disconnected or immediately adjacent (any intersection must be an empty range).

The gap operation is commutative.

@throws IllegalArgumentException if this range and {@code otherRange} have a nonempty intersection @since 27.0

Implementation

Range<C> gap(Range<C> otherRange) {
  /*
   * For an explanation of the basic principle behind this check, see
   * https://stackoverflow.com/a/35754308/28465
   *
   * In that explanation's notation, our `overlap` check would be `x1 < y2 && y1 < x2`. We've
   * flipped one part of the check so that we're using "less than" in both cases (rather than a
   * mix of "less than" and "greater than"). We've also switched to "strictly less than" rather
   * than "less than or equal to" because of *handwave* the difference between "endpoints of
   * inclusive ranges" and "Cuts."
   */
  if (lowerBound.compareTo(otherRange.upperBound) < 0 &&
      otherRange.lowerBound.compareTo(upperBound) < 0) {
    throw ArgumentError(
        "Ranges have a nonempty intersection: $this, $otherRange");
  }

  bool isThisFirst = this.lowerBound.compareTo(otherRange.lowerBound) < 0;
  Range<C> firstRange = isThisFirst ? this : otherRange;
  Range<C> secondRange = isThisFirst ? otherRange : this;
  return create(firstRange.upperBound, secondRange.lowerBound);
}