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

com.google.common.collect.super.com.google.common.collect.ImmutableSortedSet Maven / Gradle / Ivy

/*
 * Copyright (C) 2009 The Guava Authors
 *
 * 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.google.common.collect;

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

import com.google.common.annotations.Beta;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.stream.Collector;
import org.checkerframework.checker.nullness.qual.Nullable;

/**
 * GWT emulation of {@link com.google.common.collect.ImmutableSortedSet}.
 *
 * @author Hayward Chan
 */
public abstract class ImmutableSortedSet extends ForwardingImmutableSet
    implements SortedSet, SortedIterable {
  // TODO(cpovirk): split into ImmutableSortedSet/ForwardingImmutableSortedSet?

  // In the non-emulated source, this is in ImmutableSortedSetFauxverideShim,
  // which overrides ImmutableSet & which ImmutableSortedSet extends.
  // It is necessary here because otherwise the builder() method
  // would be inherited from the emulated ImmutableSet.
  // TODO(cpovirk): should we be including other methods from the shim here and
  // in ImmutableSortedMap?
  @Deprecated
  public static  ImmutableSortedSet.Builder builder() {
    throw new UnsupportedOperationException();
  }

  // TODO: Can we find a way to remove this @SuppressWarnings even for eclipse?
  @SuppressWarnings("unchecked")
  private static final Comparator NATURAL_ORDER = Ordering.natural();

  @SuppressWarnings("unchecked")
  private static final ImmutableSortedSet NATURAL_EMPTY_SET =
      new RegularImmutableSortedSet(new TreeSet(NATURAL_ORDER), false);

  static  ImmutableSortedSet emptySet(Comparator comparator) {
    checkNotNull(comparator);
    if (NATURAL_ORDER.equals(comparator)) {
      return of();
    } else {
      return new RegularImmutableSortedSet(new TreeSet(comparator), false);
    }
  }

  @Beta
  public static  Collector> toImmutableSortedSet(
      Comparator comparator) {
    return CollectCollectors.toImmutableSortedSet(comparator);
  }

  @SuppressWarnings("unchecked")
  public static  ImmutableSortedSet of() {
    return (ImmutableSortedSet) NATURAL_EMPTY_SET;
  }

  public static > ImmutableSortedSet of(E element) {
    return ofInternal(Ordering.natural(), element);
  }

  @SuppressWarnings("unchecked")
  public static > ImmutableSortedSet of(E e1, E e2) {
    return ofInternal(Ordering.natural(), e1, e2);
  }

  @SuppressWarnings("unchecked")
  public static > ImmutableSortedSet of(E e1, E e2, E e3) {
    return ofInternal(Ordering.natural(), e1, e2, e3);
  }

  @SuppressWarnings("unchecked")
  public static > ImmutableSortedSet of(E e1, E e2, E e3, E e4) {
    return ofInternal(Ordering.natural(), e1, e2, e3, e4);
  }

  @SuppressWarnings("unchecked")
  public static > ImmutableSortedSet of(
      E e1, E e2, E e3, E e4, E e5) {
    return ofInternal(Ordering.natural(), e1, e2, e3, e4, e5);
  }

  @SuppressWarnings("unchecked")
  public static > ImmutableSortedSet of(
      E e1, E e2, E e3, E e4, E e5, E e6, E... remaining) {
    int size = remaining.length + 6;
    List all = new ArrayList(size);
    Collections.addAll(all, e1, e2, e3, e4, e5, e6);
    Collections.addAll(all, remaining);
    // This is messed up. See TODO at top of file.
    return ofInternal(Ordering.natural(), (E[]) all.toArray(new Comparable[0]));
  }

  private static  ImmutableSortedSet ofInternal(
      Comparator comparator, E... elements) {
    checkNotNull(elements);
    switch (elements.length) {
      case 0:
        return emptySet(comparator);
      default:
        SortedSet delegate = new TreeSet(comparator);
        for (E element : elements) {
          checkNotNull(element);
          delegate.add(element);
        }
        return new RegularImmutableSortedSet(delegate, false);
    }
  }

  public static  ImmutableSortedSet copyOf(Collection elements) {
    return copyOfInternal((Ordering) Ordering.natural(), (Collection) elements, false);
  }

  public static  ImmutableSortedSet copyOf(Iterable elements) {
    return copyOfInternal((Ordering) Ordering.natural(), (Iterable) elements, false);
  }

  public static  ImmutableSortedSet copyOf(Iterator elements) {
    return copyOfInternal((Ordering) Ordering.natural(), (Iterator) elements);
  }

  public static > ImmutableSortedSet copyOf(E[] elements) {
    return ofInternal(Ordering.natural(), elements);
  }

  public static  ImmutableSortedSet copyOf(
      Comparator comparator, Iterable elements) {
    checkNotNull(comparator);
    return copyOfInternal(comparator, elements, false);
  }

  public static  ImmutableSortedSet copyOf(
      Comparator comparator, Collection elements) {
    checkNotNull(comparator);
    return copyOfInternal(comparator, elements, false);
  }

  public static  ImmutableSortedSet copyOf(
      Comparator comparator, Iterator elements) {
    checkNotNull(comparator);
    return copyOfInternal(comparator, elements);
  }

  @SuppressWarnings("unchecked")
  public static  ImmutableSortedSet copyOfSorted(SortedSet sortedSet) {
    Comparator comparator = sortedSet.comparator();
    if (comparator == null) {
      comparator = NATURAL_ORDER;
    }
    return copyOfInternal(comparator, sortedSet.iterator());
  }

  private static  ImmutableSortedSet copyOfInternal(
      Comparator comparator, Iterable elements, boolean fromSortedSet) {
    checkNotNull(comparator);

    boolean hasSameComparator = fromSortedSet || hasSameComparator(elements, comparator);
    if (hasSameComparator && (elements instanceof ImmutableSortedSet)) {
      @SuppressWarnings("unchecked")
      ImmutableSortedSet result = (ImmutableSortedSet) elements;
      boolean isSubset =
          (result instanceof RegularImmutableSortedSet)
              && ((RegularImmutableSortedSet) result).isSubset;
      if (!isSubset) {
        // Only return the original copy if this immutable sorted set isn't
        // a subset of another, to avoid memory leak.
        return result;
      }
    }
    return copyOfInternal(comparator, elements.iterator());
  }

  private static  ImmutableSortedSet copyOfInternal(
      Comparator comparator, Iterator elements) {
    checkNotNull(comparator);
    if (!elements.hasNext()) {
      return emptySet(comparator);
    }
    SortedSet delegate = new TreeSet(comparator);
    while (elements.hasNext()) {
      E element = elements.next();
      checkNotNull(element);
      delegate.add(element);
    }
    return new RegularImmutableSortedSet(delegate, false);
  }

  private static boolean hasSameComparator(Iterable elements, Comparator comparator) {
    if (elements instanceof SortedSet) {
      SortedSet sortedSet = (SortedSet) elements;
      Comparator comparator2 = sortedSet.comparator();
      return (comparator2 == null)
          ? comparator == Ordering.natural()
          : comparator.equals(comparator2);
    }
    return false;
  }

  // Assumes that delegate doesn't have null elements and comparator.
  static  ImmutableSortedSet unsafeDelegateSortedSet(
      SortedSet delegate, boolean isSubset) {
    return delegate.isEmpty()
        ? emptySet(delegate.comparator())
        : new RegularImmutableSortedSet(delegate, isSubset);
  }

  private final transient SortedSet sortedDelegate;

  /**
   * Scary constructor for ContiguousSet. This constructor (in this file, the GWT emulation of
   * ImmutableSortedSet) creates an empty sortedDelegate, which, in a vacuum, sets this object's
   * contents to empty. By contrast, the non-GWT constructor with the same signature uses the
   * comparator only as a comparator. It does NOT assume empty contents. (It requires an
   * implementation of iterator() to define its contents, and methods like contains() are
   * implemented in terms of that method (though they will likely be overridden by subclasses for
   * performance reasons).) This means that a call to this method have can different behavior in GWT
   * and non-GWT environments UNLESS subclasses are careful to always override all methods
   * implemented in terms of sortedDelegate (except comparator()).
   */
  ImmutableSortedSet(Comparator comparator) {
    this(Sets.newTreeSet(comparator));
  }

  ImmutableSortedSet(SortedSet sortedDelegate) {
    super(sortedDelegate);
    this.sortedDelegate = Collections.unmodifiableSortedSet(sortedDelegate);
  }

  public Comparator comparator() {
    return sortedDelegate.comparator();
  }

  @Override // needed to unify SortedIterable and Collection iterator() methods
  public UnmodifiableIterator iterator() {
    return super.iterator();
  }

  @Override
  public Object[] toArray() {
    return ObjectArrays.toArrayImpl(this);
  }

  @Override
  public  T[] toArray(T[] other) {
    return ObjectArrays.toArrayImpl(this, other);
  }

  @Override
  public boolean contains(@Nullable Object object) {
    try {
      // This set never contains null.  We need to explicitly check here
      // because some comparator might throw NPE (e.g. the natural ordering).
      return object != null && sortedDelegate.contains(object);
    } catch (ClassCastException e) {
      return false;
    }
  }

  @Override
  public boolean containsAll(Collection targets) {
    for (Object target : targets) {
      if (target == null) {
        // This set never contains null.  We need to explicitly check here
        // because some comparator might throw NPE (e.g. the natural ordering).
        return false;
      }
    }
    try {
      return sortedDelegate.containsAll(targets);
    } catch (ClassCastException e) {
      return false;
    }
  }

  public E first() {
    return sortedDelegate.first();
  }

  public ImmutableSortedSet headSet(E toElement) {
    checkNotNull(toElement);
    try {
      return unsafeDelegateSortedSet(sortedDelegate.headSet(toElement), true);
    } catch (IllegalArgumentException e) {
      return emptySet(comparator());
    }
  }

  E higher(E e) {
    checkNotNull(e);
    Iterator iterator = tailSet(e).iterator();
    while (iterator.hasNext()) {
      E higher = iterator.next();
      if (comparator().compare(e, higher) < 0) {
        return higher;
      }
    }
    return null;
  }

  public E ceiling(E e) {
    ImmutableSortedSet set = tailSet(e, true);
    return !set.isEmpty() ? set.first() : null;
  }

  public E floor(E e) {
    ImmutableSortedSet set = headSet(e, true);
    return !set.isEmpty() ? set.last() : null;
  }

  public ImmutableSortedSet headSet(E toElement, boolean inclusive) {
    checkNotNull(toElement);
    if (inclusive) {
      E tmp = higher(toElement);
      if (tmp == null) {
        return this;
      }
      toElement = tmp;
    }
    return headSet(toElement);
  }

  public E last() {
    return sortedDelegate.last();
  }

  public ImmutableSortedSet subSet(E fromElement, E toElement) {
    return subSet(fromElement, true, toElement, false);
  }

  ImmutableSortedSet subSet(
      E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) {
    checkNotNull(fromElement);
    checkNotNull(toElement);
    int cmp = comparator().compare(fromElement, toElement);
    checkArgument(cmp <= 0, "fromElement (%s) is less than toElement (%s)", fromElement, toElement);
    if (cmp == 0 && !(fromInclusive && toInclusive)) {
      return emptySet(comparator());
    }
    return tailSet(fromElement, fromInclusive).headSet(toElement, toInclusive);
  }

  public ImmutableSortedSet tailSet(E fromElement) {
    checkNotNull(fromElement);
    try {
      return unsafeDelegateSortedSet(sortedDelegate.tailSet(fromElement), true);
    } catch (IllegalArgumentException e) {
      return emptySet(comparator());
    }
  }

  public ImmutableSortedSet tailSet(E fromElement, boolean inclusive) {
    checkNotNull(fromElement);
    if (!inclusive) {
      E tmp = higher(fromElement);
      if (tmp == null) {
        return emptySet(comparator());
      }
      fromElement = tmp;
    }
    return tailSet(fromElement);
  }

  public static  Builder orderedBy(Comparator comparator) {
    return new Builder(comparator);
  }

  public static > Builder reverseOrder() {
    return new Builder(Ordering.natural().reverse());
  }

  public static > Builder naturalOrder() {
    return new Builder(Ordering.natural());
  }

  public static final class Builder extends ImmutableSet.Builder {
    private final Comparator comparator;

    public Builder(Comparator comparator) {
      this.comparator = checkNotNull(comparator);
    }

    @Override
    public Builder add(E element) {
      super.add(element);
      return this;
    }

    @Override
    public Builder add(E... elements) {
      super.add(elements);
      return this;
    }

    @Override
    public Builder addAll(Iterable elements) {
      super.addAll(elements);
      return this;
    }

    @Override
    public Builder addAll(Iterator elements) {
      super.addAll(elements);
      return this;
    }

    Builder combine(Builder builder) {
      super.combine(builder);
      return this;
    }

    @Override
    public ImmutableSortedSet build() {
      return copyOfInternal(comparator, contents.iterator());
    }
  }
}