Skip to content

Instantly share code, notes, and snippets.

@TuomasKiviaho
Created April 13, 2019 04:49
Show Gist options
  • Save TuomasKiviaho/2ccfa28d26956c46fa8ec70c6c37cb97 to your computer and use it in GitHub Desktop.
Save TuomasKiviaho/2ccfa28d26956c46fa8ec70c6c37cb97 to your computer and use it in GitHub Desktop.
package com.google.common.collect;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Collection;
import java.util.NoSuchElementException;
import java.util.function.Predicate;
@SuppressWarnings("serial")
public class SemiContiguousSet<C extends Comparable<? super C>> extends ContiguousSet<C>
{
public static <C extends Comparable<? super C>> ContiguousSet<C> create(
Range<C> range, DiscreteDomain<C> domain, Predicate<C> predicate)
{
checkNotNull(range);
checkNotNull(domain);
Range<C> effectiveRange = range;
try
{
if (!range.hasLowerBound())
{
effectiveRange = effectiveRange.intersection(
Range.atLeast(domain.minValue()));
}
if (!range.hasUpperBound())
{
effectiveRange = effectiveRange.intersection(
Range.atMost(domain.maxValue()));
}
}
catch (NoSuchElementException e)
{
throw new IllegalArgumentException(e);
}
C lowerEndpoint = range.lowerEndpoint();
C upperEndpoint = range.upperEndpoint();
boolean empty = effectiveRange.isEmpty() || Range.compareOrThrow(
BoundType.CLOSED.equals(range.lowerBoundType())
&& predicate.test(lowerEndpoint) ? lowerEndpoint
: domain.next(lowerEndpoint),
BoundType.CLOSED.equals(range.upperBoundType())
&& predicate.test(upperEndpoint) ? upperEndpoint
: domain.previous(upperEndpoint)) > 0;
return empty ? new EmptyContiguousSet<>(domain)
: new SemiContiguousSet<>(effectiveRange, domain, predicate);
}
private Range<C> range;
private Predicate<C> predicate;
public SemiContiguousSet(Range<C> range, DiscreteDomain<C> domain, Predicate<C> predicate)
{
super(domain);
this.range = range;
this.predicate = predicate;
}
private ContiguousSet<C> intersectionInCurrentDomain(Range<C> other)
{
return range.isConnected(other)
? new SemiContiguousSet<>(range.intersection(other), domain, predicate)
: new EmptyContiguousSet<>(domain);
}
@Override
ContiguousSet<C> headSetImpl(C toElement, boolean inclusive)
{
return intersectionInCurrentDomain(
Range.upTo(toElement, BoundType.forBoolean(inclusive)));
}
@Override
ContiguousSet<C> subSetImpl(C fromElement, boolean fromInclusive, C toElement,
boolean toInclusive)
{
return !(fromInclusive || toInclusive) && fromElement.compareTo(toElement) == 0
? new EmptyContiguousSet<>(domain)
: intersectionInCurrentDomain(
Range.range(fromElement, BoundType.forBoolean(fromInclusive), toElement,
BoundType.forBoolean(toInclusive)));
}
@Override
ContiguousSet<C> tailSetImpl(C fromElement, boolean inclusive)
{
return intersectionInCurrentDomain(
Range.downTo(fromElement, BoundType.forBoolean(inclusive)));
}
@SuppressWarnings("unchecked")
@Override
int indexOf(Object target)
{
return this.contains(target) ? (int) this.domain.distance(first(), (C) target)
: -1;
}
@Override
public UnmodifiableIterator<C> iterator()
{
return new AbstractSequentialIterator<C>(first())
{
final C last = last();
@Override
protected C computeNext(C previous)
{
C next = previous == null ? null : domain.next(previous);
return last != null && next.compareTo(last) > 0 ? null : next;
}
};
}
@Override
public UnmodifiableIterator<C> descendingIterator()
{
return new AbstractSequentialIterator<C>(last())
{
final C first = first();
@Override
protected C computeNext(C next)
{
C previous = next == null ? null : domain.previous(next);
return first != null && previous.compareTo(first) < 0 ? null : previous;
}
};
}
@Override
boolean isPartialView()
{
return false;
}
@Override
public C first()
{
C lowerEndpoint = this.range.lowerEndpoint();
return BoundType.CLOSED.equals(this.range.lowerBoundType())
&& this.predicate.test(lowerEndpoint) ? lowerEndpoint
: this.domain.next(lowerEndpoint);
}
@Override
public C last()
{
C upperEndpoint = this.range.upperEndpoint();
return BoundType.CLOSED.equals(this.range.upperBoundType())
&& this.predicate.test(upperEndpoint) ? upperEndpoint
: this.domain.previous(upperEndpoint);
}
@Override
public int size()
{
long distance = this.domain.distance(this.first(), this.last());
return distance >= Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) distance + 1;
}
@Override
public boolean contains(Object object)
{
try
{
@SuppressWarnings("unchecked")
C element = (C) object;
return object != null && this.range.contains(element)
&& this.predicate.test(element);
}
catch (ClassCastException e)
{
return false;
}
}
@Override
public boolean containsAll(Collection<?> targets)
{
return Collections2.containsAllImpl(this, targets);
}
@Override
public boolean isEmpty()
{
return this.range().isEmpty();
}
@Override
public ContiguousSet<C> intersection(ContiguousSet<C> other)
{
checkNotNull(other);
checkArgument(this.domain.equals(other.domain));
if (other.isEmpty())
{
return other;
}
else
{
C lowerEndpoint = Ordering.natural().max(this.first(), other.first());
C upperEndpoint = Ordering.natural().min(this.last(), other.last());
return (lowerEndpoint.compareTo(upperEndpoint) <= 0)
? new SemiContiguousSet<>(Range.closed(lowerEndpoint, upperEndpoint),
domain, predicate)
: new EmptyContiguousSet<>(domain);
}
}
@Override
public Range<C> range()
{
return Range.closed(this.first(), this.last());
}
@Override
public Range<C> range(BoundType lowerBoundType, BoundType upperBoundType)
{
Range<C> range = this.range();
return BoundType.CLOSED.equals(lowerBoundType)
&& BoundType.CLOSED.equals(upperBoundType) ? range : Range.create(range.lowerBound.withLowerBoundType(lowerBoundType, this.domain),
range.upperBound.withUpperBoundType(upperBoundType, this.domain));
}
@Override
public boolean equals(Object object)
{
if (object == this)
{
return true;
}
else if (object instanceof SemiContiguousSet)
{
SemiContiguousSet<?> that = (SemiContiguousSet<?>) object;
return this.domain.equals(that.domain)
&& this.predicate.equals(that.predicate) && this.range.equals(that.range);
}
return super.equals(object);
}
@Override
public int hashCode()
{
return Sets.hashCodeImpl(this);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment