@Override
    public @NotNull LongRangeSet join(@NotNull LongRangeSet other) {
      if (other.isEmpty() || other == this) return this;
      if (other.contains(myValue)) return other;
      if (other instanceof Point) {
        long value1 = Math.min(myValue, ((Point)other).myValue);
        long value2 = Math.max(myValue, ((Point)other).myValue);
        return value1 + 1 == value2
               ? range(value1, value2)
               : new RangeSet(new long[]{value1, value1, value2, value2});
      }
      if (other instanceof ModRange) {
        return other.join(this);
      }
      if (other instanceof Range) {
        if (myValue < other.min()) {
          return myValue + 1 == other.min()
                 ? range(myValue, other.max())
                 : new RangeSet(new long[]{myValue, myValue, other.min(), other.max()});
        }
        else {
          assert myValue > other.max();
          return myValue - 1 == other.max()
                 ? range(other.min(), myValue)
                 : new RangeSet(new long[]{other.min(), other.max(), myValue, myValue});
        }
      }
      long[] longs = other.asRangeArray();
      int pos = -Arrays.binarySearch(longs, myValue) - 1;
      assert pos >= 0 && pos % 2 == 0;
      boolean touchLeft = pos > 0 && longs[pos - 1] + 1 == myValue;
      boolean touchRight = pos < longs.length - 1 && myValue + 1 == longs[pos];
      long[] result;
      if (touchLeft) {
        if (touchRight) {
          result = new long[longs.length - 2];
          System.arraycopy(longs, 0, result, 0, pos - 1);
          System.arraycopy(longs, pos + 1, result, pos - 1, longs.length - pos - 1);
        }
        else {
          result = longs.clone();
          result[pos - 1] = myValue;
        }
      }
      else {
        if (touchRight) {
          result = longs.clone();
          result[pos] = myValue;
        }
        else {
          result = new long[longs.length + 2];
          System.arraycopy(longs, 0, result, 0, pos);
          result[pos] = result[pos + 1] = myValue;
          System.arraycopy(longs, pos, result, pos + 2, longs.length - pos);
        }
      }
      return fromRanges(result, result.length);
    }
@Override
    public @NotNull LongRangeSet join(@NotNull LongRangeSet other)