blob: c01d3a29c35b1f0006a9f3831510969f8b28f40d [file] [log] [blame]
/*=============================================================================#
# Copyright (c) 2009, 2021 Stephan Wahlbrink and others.
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License 2.0 which is available at
# https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
# which is available at https://www.apache.org/licenses/LICENSE-2.0.
#
# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
#
# Contributors:
# Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
#=============================================================================*/
package org.eclipse.statet.jcommons.text.core;
import static org.eclipse.statet.jcommons.lang.ObjectUtils.nonNullAssert;
import org.eclipse.statet.jcommons.lang.Immutable;
import org.eclipse.statet.jcommons.lang.NonNullByDefault;
import org.eclipse.statet.jcommons.lang.Nullable;
@NonNullByDefault
public class BasicTextLineInformation implements TextLineInformation, Immutable {
private final int[] startOffsets;
private final int textLength;
public BasicTextLineInformation(final int[] offsets, final int textLength) {
this.startOffsets= nonNullAssert(offsets);
this.textLength= textLength;
}
@Override
public int getNumberOfLines() {
return this.startOffsets.length;
}
@Override
public int getLineOfOffset(final int offset) {
if (offset < 0 || offset > this.textLength) {
throw new IllegalArgumentException("offset= " + offset); //$NON-NLS-1$
}
if (this.startOffsets.length == 0) {
return 0;
}
int low= 0;
int high= this.startOffsets.length - 1;
while (low <= high) {
final int mid= (low + high) >> 1;
final int lineOffset= this.startOffsets[mid];
if (lineOffset < offset) {
low= mid + 1;
}
else if (lineOffset > offset) {
high= mid - 1;
}
else {
return mid;
}
}
return low - 1;
}
@Override
public int getStartOffset(final int line) {
if (line < 0 || line >= this.startOffsets.length) {
throw new IllegalArgumentException("line= " + line); //$NON-NLS-1$
}
return this.startOffsets[line];
}
@Override
public int getEndOffset(final int line) {
if (line < 0 || line >= this.startOffsets.length) {
throw new IllegalArgumentException("line= " + line); //$NON-NLS-1$
}
return (line + 1 == this.startOffsets.length) ?
this.textLength :
this.startOffsets[line + 1];
}
@Override
public int getLength(final int line) {
if (line < 0 || line >= this.startOffsets.length) {
throw new IllegalArgumentException("line= " + line); //$NON-NLS-1$
}
return (line + 1 == this.startOffsets.length) ?
(this.textLength - this.startOffsets[line]) :
(this.startOffsets[line + 1] - this.startOffsets[line]);
}
@Override
public TextRegion getRegion(final int line) {
if (line < 0 || line >= this.startOffsets.length) {
throw new IllegalArgumentException("line= " + line); //$NON-NLS-1$
}
return new BasicTextRegion(this.startOffsets[line],
(line + 1 == this.startOffsets.length) ?
this.textLength :
this.startOffsets[line + 1] );
}
@Override
public int hashCode() {
return this.startOffsets.hashCode() + this.textLength;
}
@Override
public boolean equals(final @Nullable Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof TextLineInformation) {
final TextLineInformation other= (TextLineInformation) obj;
final int n= getNumberOfLines();
if (n != other.getNumberOfLines()) {
return false;
}
for (int line= 0; line <= n; line++) {
if (getStartOffset(line) != other.getStartOffset(line)
|| getEndOffset(line) != other.getEndOffset(line) ) {
return false;
}
}
return true;
}
return false;
}
}