All Downloads are FREE. Search and download functionalities are using the official Maven repository.

edu.isi.nlp.strings.offsets.OffsetRange Maven / Gradle / Ivy

The newest version!
package edu.isi.nlp.strings.offsets;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.base.Function;
import com.google.common.base.Objects;
import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.collect.Ordering;
import com.google.common.collect.Range;
import com.google.common.primitives.Ints;
import java.util.Comparator;

/** Represents an inclusive range of offsets. */
public class OffsetRange> {

  private final OffsetType startInclusive;
  private final OffsetType endInclusive;

  @JsonCreator
  public static >
      OffsetRange fromInclusiveEndpoints(
          @JsonProperty("start") OffsetType startInclusive,
          @JsonProperty("end") OffsetType endInclusive) {
    checkArgument(startInclusive.asInt() <= endInclusive.asInt());
    return new OffsetRange<>(startInclusive, endInclusive);
  }

  private OffsetRange(OffsetType startInclusive, OffsetType endInclusive) {
    checkArgument(startInclusive.asInt() <= endInclusive.asInt());
    this.startInclusive = checkNotNull(startInclusive);
    this.endInclusive = checkNotNull(endInclusive);
  }

  @JsonProperty("start")
  public OffsetType startInclusive() {
    return startInclusive;
  }

  @JsonProperty("end")
  public OffsetType endInclusive() {
    return endInclusive;
  }

  public Range asRange() {
    return Range.closed(startInclusive, endInclusive);
  }

  public int length() {
    return endInclusive.asInt() - startInclusive().asInt() + 1;
  }

  @Override
  public int hashCode() {
    return Objects.hashCode(startInclusive, endInclusive);
  }

  @Override
  public boolean equals(Object obj) {
    if (this == obj) {
      return true;
    }
    if (obj == null || getClass() != obj.getClass()) {
      return false;
    }
    final OffsetRange other = (OffsetRange) obj;
    return Objects.equal(this.startInclusive, other.startInclusive)
        && Objects.equal(this.endInclusive, other.endInclusive);
  }

  public static > Ordering> byLengthOrdering() {
    return new Ordering>() {
      @Override
      public int compare(final OffsetRange left, final OffsetRange right) {
        return Ints.compare(left.length(), right.length());
      }
    };
  }

  private static > Function, T> toStartInclusiveFunction() {
    return new Function, T>() {
      @Override
      public T apply(OffsetRange x) {
        return x.startInclusive();
      }
    };
  }

  private static > Function, T> toEndInclusiveFunction() {
    return new Function, T>() {
      @Override
      public T apply(OffsetRange x) {
        return x.endInclusive();
      }
    };
  }

  /**
   * Provides an {@link Ordering} of {@link OffsetRange}s by their start position. Note that this is
   * not a total ordering because {@link OffsetRange}s with the same start position but different
   * end positions will compare as equal.
   *
   * 

Consider producing a compound ordering with {@link #byEndOrdering()} using {@link * Ordering#compound(Comparator)} or using one of the predefined total orderings. */ public static > Ordering> byStartOrdering() { return Ordering.natural().onResultOf(OffsetRange.toStartInclusiveFunction()); } /** * Provides an {@link Ordering} of {@link OffsetRange}s by their end position. Note that this is * not a total ordering because {@link OffsetRange}s with the same end position but different * start positions will compare as equal. * *

Consider producing a compound ordering with {@link #byStartOrdering()} using {@link * Ordering#compound(Comparator)} or using one of the predefined total orderings. */ public static > Ordering> byEndOrdering() { return Ordering.natural().onResultOf(OffsetRange.toEndInclusiveFunction()); } /** * Provides a total {@link Ordering} over {@link OffsetRange}s by their start position, breaking * ties by placing the earlier end position first. */ public static > Ordering> byEarlierStartEarlierEndOrdering() { return Ordering.natural() .onResultOf(OffsetRange.toStartInclusiveFunction()) .compound(Ordering.natural().onResultOf(OffsetRange.toEndInclusiveFunction())); } /** * Provides a total {@link Ordering} over {@link OffsetRange}s by their start position, breaking * ties by placing the later end position first. */ public static > Ordering> byEarlierStartLaterEndOrdering() { return Ordering.natural() .onResultOf(OffsetRange.toStartInclusiveFunction()) .compound( Ordering.natural().onResultOf(OffsetRange.toEndInclusiveFunction()).reverse()); } public static OffsetRange inclusiveCharOffsetRange( int startInclusive, int endInclusive) { return fromInclusiveEndpoints( CharOffset.asCharOffset(startInclusive), CharOffset.asCharOffset(endInclusive)); } /** Prefer {@link #inclusiveCharOffsetRange(int, int)} */ public static OffsetRange charOffsetRange(int startInclusive, int endInclusive) { return inclusiveCharOffsetRange(startInclusive, endInclusive); } public static OffsetRange byteOffsetRange( final int startInclusive, final int endInclusive) { return OffsetRange.fromInclusiveEndpoints( ByteOffset.asByteOffset(startInclusive), ByteOffset.asByteOffset(endInclusive)); } /** This returns optional because it is not possible to represent an empty offset span */ public static Optional> charOffsetsOfWholeString(String s) { if (s.isEmpty()) { return Optional.absent(); } return Optional.of(charOffsetRange(0, s.length() - 1)); } /** * Returns a new {@code OffsetRange} of the same type with the start and end points shifted by the * specified amount. */ public OffsetRange shiftedCopy(final int shiftAmount) { return new OffsetRange<>( startInclusive().shiftedCopy(shiftAmount), endInclusive().shiftedCopy(shiftAmount)); } public boolean overlaps(OffsetRange other) { return asRange().isConnected(other.asRange()); } public Optional> intersection(OffsetRange other) { final Range meAsRange = asRange(); final Range otherAsRange = other.asRange(); if (meAsRange.isConnected(otherAsRange)) { final Range intersectionRange = meAsRange.intersection(otherAsRange); return Optional.of( fromInclusiveEndpoints( intersectionRange.lowerEndpoint(), intersectionRange.upperEndpoint())); } else { return Optional.absent(); } } /** Returns if the given offset is within the inclusive bounds of this range. */ public boolean contains(final OffsetType x) { return x.asInt() >= startInclusive().asInt() && x.asInt() <= endInclusive().asInt(); } /** Returns if the given inclusive offset range is within the inclusive bounds of this range. */ public boolean contains(OffsetRange other) { return asRange().encloses(other.asRange()); } public static > Predicate> containedInPredicate( final OffsetRange container) { return new Predicate>() { @Override public boolean apply(OffsetRange input) { return container.contains(input); } }; } /** * Returns this range with its start and end positions clipped to fit within {@code bounds}. If * this does not intersect {@code bounds}, returns {@link * com.google.common.base.Optional#absent()} . */ public Optional> clipToBounds(OffsetRange bounds) { if (bounds.contains(this)) { return Optional.of(this); } if (!bounds.overlaps(this)) { return Optional.absent(); } final OffsetType newLowerBound; final OffsetType newUpperBound; if (bounds.startInclusive().asInt() > startInclusive().asInt()) { newLowerBound = bounds.startInclusive(); } else { newLowerBound = startInclusive(); } if (bounds.endInclusive().asInt() < endInclusive().asInt()) { newUpperBound = bounds.endInclusive(); } else { newUpperBound = endInclusive(); } return Optional.of(OffsetRange.fromInclusiveEndpoints(newLowerBound, newUpperBound)); } public static Function, Integer> lengthFunction() { return LengthFunction.INSTANCE; } private enum LengthFunction implements Function, Integer> { INSTANCE { @Override public Integer apply(final OffsetRange input) { return input.length(); } } } @Override public String toString() { return "[" + startInclusive().toString() + "-" + endInclusive().toString() + "]"; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy