@Override
    public @NotNull LongRangeSet subtract(@NotNull LongRangeSet other) {
      if (other.isEmpty()) return this;
      if (other == this) return Empty.EMPTY;
      if (other instanceof Point) {
        long value = ((Point)other).myValue;
        if (value < myFrom || value > myTo) return this;
        if (value == myFrom) return range(myFrom + 1, myTo);
        if (value == myTo) return range(myFrom, myTo - 1);
        return new RangeSet(new long[]{myFrom, value - 1, value + 1, myTo});
      }
      if (other instanceof Range) {
        LongRangeSet toJoin = Empty.EMPTY;
        long from = ((Range)other).myFrom;
        long to = ((Range)other).myTo;
        if (to < myFrom || from > myTo) return this;
        if (other instanceof ModRange modRange) {
          long newBits = ~modRange.myBits;
          if (modRange.myMod < 64) {
            newBits &= (1L << modRange.myMod) - 1;
          }
          toJoin = modRange(Math.max(from, myFrom), Math.min(to, myTo), modRange.myMod, newBits);
        }
        if (from <= myFrom && to >= myTo) return toJoin;
        if (from > myFrom && to < myTo) {
          return new RangeSet(new long[]{myFrom, from - 1, to + 1, myTo}).join(toJoin);
        }
        if (from <= myFrom) {
          return range(to + 1, myTo).join(toJoin);
        }
        assert to >= myTo;
        return range(myFrom, from - 1).join(toJoin);
      }
      long[] ranges = ((RangeSet)other).myRanges;
      LongRangeSet result = this;
      for (int i = 0; i < ranges.length; i += 2) {
        result = result.subtract(range(ranges[i], ranges[i + 1]));
        if (result.isEmpty()) return result;
      }
      return result;
    }
@Override
    public @NotNull LongRangeSet subtract(@NotNull LongRangeSet other)