blob: 4c09b969a5709537dbe780fcb64549124959b9a8 [file] [log] [blame]
/*
* Copyright 2000-2009 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.openapi.util;
import com.intellij.openapi.diagnostic.Logger;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.Serializable;
public class TextRange implements Segment, Serializable {
private static final Logger LOG = Logger.getInstance(TextRange.class);
private static final long serialVersionUID = -670091356599757430L;
public static final TextRange EMPTY_RANGE = new TextRange(0,0);
private final int myStartOffset;
private final int myEndOffset;
public TextRange(int startOffset, int endOffset) {
this(startOffset, endOffset, true);
}
/**
* @param checkForProperTextRange <code>true</code> if offsets should be checked by {@link #assertProperRange(int, int, Object)}
* @see com.intellij.openapi.util.UnfairTextRange
*/
protected TextRange(int startOffset, int endOffset, boolean checkForProperTextRange) {
myStartOffset = startOffset;
myEndOffset = endOffset;
if (checkForProperTextRange) {
assertProperRange(this);
}
}
@Override
public final int getStartOffset() {
return myStartOffset;
}
@Override
public final int getEndOffset() {
return myEndOffset;
}
public final int getLength() {
return myEndOffset - myStartOffset;
}
public boolean equals(Object obj) {
if (!(obj instanceof TextRange)) return false;
TextRange range = (TextRange)obj;
return myStartOffset == range.myStartOffset && myEndOffset == range.myEndOffset;
}
public int hashCode() {
return myStartOffset + myEndOffset;
}
public boolean contains(@NotNull TextRange range) {
return containsRange(range.getStartOffset(), range.getEndOffset());
}
public boolean containsRange(int startOffset, int endOffset) {
return myStartOffset <= startOffset && myEndOffset >= endOffset;
}
public boolean containsOffset(int offset) {
return myStartOffset <= offset && offset <= myEndOffset;
}
public String toString() {
return "(" + myStartOffset + "," + myEndOffset + ")";
}
public boolean contains(int offset) {
return myStartOffset <= offset && offset < myEndOffset;
}
@NotNull
public String substring(@NotNull String str) {
try {
return str.substring(myStartOffset, myEndOffset);
}
catch (StringIndexOutOfBoundsException e) {
throw new StringIndexOutOfBoundsException("Can't extract " + this + " range from " + str);
}
}
@NotNull
public CharSequence subSequence(@NotNull CharSequence str) {
try {
return str.subSequence(myStartOffset, myEndOffset);
}
catch (IndexOutOfBoundsException e) {
throw new IndexOutOfBoundsException("Can't extract " + this + " range from " + str);
}
}
@NotNull
public TextRange cutOut(@NotNull TextRange subRange) {
assert subRange.getStartOffset() <= getLength() : subRange + "; this="+this;
assert subRange.getEndOffset() <= getLength() : subRange + "; this="+this;
return new TextRange(myStartOffset + subRange.getStartOffset(), Math.min(myEndOffset, myStartOffset + subRange.getEndOffset()));
}
@NotNull
public TextRange shiftRight(int delta) {
if (delta == 0) return this;
return new TextRange(myStartOffset + delta, myEndOffset + delta);
}
@NotNull
public TextRange grown(int lengthDelta) {
return from(myStartOffset, getLength() + lengthDelta);
}
@NotNull
public static TextRange from(int offset, int length) {
return create(offset, offset + length);
}
@NotNull
public static TextRange create(int startOffset, int endOffset) {
return new TextRange(startOffset, endOffset);
}
@NotNull
public static TextRange create(@NotNull Segment segment) {
return create(segment.getStartOffset(), segment.getEndOffset());
}
public static boolean areSegmentsEqual(@NotNull Segment segment1, @NotNull Segment segment2) {
return segment1.getStartOffset() == segment2.getStartOffset()
&& segment1.getEndOffset() == segment2.getEndOffset();
}
@NotNull
public String replace(@NotNull String original, @NotNull String replacement) {
try {
String beginning = original.substring(0, getStartOffset());
String ending = original.substring(getEndOffset(), original.length());
return beginning + replacement + ending;
}
catch (StringIndexOutOfBoundsException e) {
throw new StringIndexOutOfBoundsException("Can't replace " + this + " range from '" + original + "' with '" + replacement + "'");
}
}
public boolean intersects(@NotNull TextRange textRange) {
return intersects((Segment)textRange);
}
public boolean intersects(@NotNull Segment textRange) {
return intersects(textRange.getStartOffset(), textRange.getEndOffset());
}
public boolean intersects(int startOffset, int endOffset) {
return Math.max(myStartOffset, startOffset) <= Math.min(myEndOffset, endOffset);
}
public boolean intersectsStrict(@NotNull TextRange textRange) {
return intersectsStrict(textRange.getStartOffset(), textRange.getEndOffset());
}
public boolean intersectsStrict(int startOffset, int endOffset) {
return Math.max(myStartOffset, startOffset) < Math.min(myEndOffset, endOffset);
}
@Nullable
public TextRange intersection(@NotNull TextRange range) {
if (!intersects(range)) return null;
return new TextRange(Math.max(myStartOffset, range.getStartOffset()), Math.min(myEndOffset, range.getEndOffset()));
}
public boolean isEmpty() {
return myStartOffset >= myEndOffset;
}
@NotNull
public TextRange union(@NotNull TextRange textRange) {
return new TextRange(Math.min(myStartOffset, textRange.getStartOffset()), Math.max(myEndOffset, textRange.getEndOffset()));
}
public boolean equalsToRange(int startOffset, int endOffset) {
return startOffset == myStartOffset && endOffset == myEndOffset;
}
public static TextRange allOf(String s) {
return new TextRange(0, s.length());
}
public static void assertProperRange(@NotNull Segment range) throws AssertionError {
assertProperRange(range, "");
}
public static void assertProperRange(@NotNull Segment range, Object message) throws AssertionError {
assertProperRange(range.getStartOffset(), range.getEndOffset(), message);
}
public static void assertProperRange(int startOffset, int endOffset, Object message) {
if (startOffset > endOffset) {
LOG.error("Invalid range specified: (" + startOffset + "," + endOffset + "); " + message);
}
if (startOffset < 0) {
LOG.error("Negative start offset: (" + startOffset + "," + endOffset + "); " + message);
}
}
}