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

org.apache.calcite.util.CompatibleGuava11 Maven / Gradle / Ivy

There is a newer version: 1.17.0-flink-r3
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to you 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 org.apache.calcite.util;

import com.google.common.base.Function;
import com.google.common.collect.Collections2;
import com.google.common.collect.ForwardingSet;
import com.google.common.collect.ImmutableSortedMap;
import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.Maps;
import com.google.common.collect.Multiset;
import com.google.common.collect.Sets;

import java.util.AbstractCollection;
import java.util.AbstractMap;
import java.util.AbstractSet;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.NavigableMap;
import java.util.NavigableSet;
import java.util.Objects;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;

/** Helper methods to provide modern Guava functionality based on Guava 11.
 *
 * @see Compatible
 */
class CompatibleGuava11 {
  private CompatibleGuava11() {}

  public static  Map asMap(
      Set set, Function function) {
    return new AsMapView(set, function);
  }

  /**
   * {@link AbstractSet} substitute without the potentially-quadratic
   * {@code removeAll} implementation.
   *
   * @param  element type
   */
  abstract static class ImprovedAbstractSet extends AbstractSet {
    @Override public boolean removeAll(Collection c) {
      return removeAllImpl(this, c);
    }

    @Override public boolean retainAll(Collection c) {
      return super.retainAll(Objects.requireNonNull(c)); // GWT compatibility
    }
  }

  /**
   * Remove each element in an iterable from a set.
   */
  static boolean removeAllImpl(Set set, Iterator iterator) {
    boolean changed = false;
    while (iterator.hasNext()) {
      changed |= set.remove(iterator.next());
    }
    return changed;
  }

  static boolean removeAllImpl(Set set, Collection collection) {
    Objects.requireNonNull(collection); // for GWT
    if (collection instanceof Multiset) {
      collection = ((Multiset) collection).elementSet();
    }

    // AbstractSet.removeAll(List) has quadratic behavior if the list size
    // is just less than the set's size.  We augment the test by
    // assuming that sets have fast contains() performance, and other
    // collections don't.  See
    // http://code.google.com/p/guava-libraries/issues/detail?id=1013
    if (collection instanceof Set && collection.size() > set.size()) {
      Iterator setIterator = set.iterator();
      boolean changed = false;
      while (setIterator.hasNext()) {
        if (collection.contains(setIterator.next())) {
          changed = true;
          setIterator.remove();
        }
      }
      return changed;
    } else {
      return removeAllImpl(set, collection.iterator());
    }
  }

  /** ImprovedAbstractMap.
   *
   * @param  key type
   * @param  value type */
  abstract static class ImprovedAbstractMap extends AbstractMap {
    /**
     * Creates the entry set to be returned by {@link #entrySet()}. This method
     * is invoked at most once on a given map, at the time when {@code entrySet}
     * is first called.
     */
    protected abstract Set> createEntrySet();

    private Set> entrySet;

    @Override public Set> entrySet() {
      Set> result = entrySet;
      if (result == null) {
        entrySet = result = createEntrySet();
      }
      return result;
    }

    private Set keySet;

    @Override public Set keySet() {
      Set result = keySet;
      if (result == null) {
        return keySet = new KeySet() {
          @Override Map map() {
            return ImprovedAbstractMap.this;
          }
        };
      }
      return result;
    }

    private Collection values;

    @Override public Collection values() {
      Collection result = values;
      if (result == null) {
        return values = new Values() {
          @Override Map map() {
            return ImprovedAbstractMap.this;
          }
        };
      }
      return result;
    }
  }

  static  Iterator keyIterator(
      Iterator> entryIterator) {
    return new TransformedIterator, K>(entryIterator) {
      @Override K transform(Map.Entry entry) {
        return entry.getKey();
      }
    };
  }

  /** KeySet.
   *
   * @param  key type
   * @param  value type */
  abstract static class KeySet extends ImprovedAbstractSet {
    abstract Map map();

    @Override public Iterator iterator() {
      return keyIterator(map().entrySet().iterator());
    }

    @Override public int size() {
      return map().size();
    }

    @Override public boolean isEmpty() {
      return map().isEmpty();
    }

    @Override public boolean contains(Object o) {
      return map().containsKey(o);
    }

    @Override public boolean remove(Object o) {
      if (contains(o)) {
        map().remove(o);
        return true;
      }
      return false;
    }

    @Override public void clear() {
      map().clear();
    }
  }

  private static  Set removeOnlySet(final Set set) {
    return new ForwardingSet() {
      @Override protected Set delegate() {
        return set;
      }

      @Override public boolean add(E element) {
        throw new UnsupportedOperationException();
      }

      @Override public boolean addAll(Collection es) {
        throw new UnsupportedOperationException();
      }
    };
  }

  private static  Iterator> asSetEntryIterator(
      Set set, final Function function) {
    return new TransformedIterator>(set.iterator()) {
      @Override Map.Entry transform(K key) {
        return Maps.immutableEntry(key, function.apply(key));
      }
    };
  }

  /** AsMapView.
   *
   * @param  key type
   * @param  value type */
  private static class AsMapView extends ImprovedAbstractMap {
    private final Set set;
    final Function function;

    Set backingSet() {
      return set;
    }

    AsMapView(Set set, Function function) {
      this.set = Objects.requireNonNull(set);
      this.function = Objects.requireNonNull(function);
    }

    @Override public Set keySet() {
      // probably not worth caching
      return removeOnlySet(backingSet());
    }

    @Override public Collection values() {
      // probably not worth caching
      return Collections2.transform(set, function);
    }

    @Override public int size() {
      return backingSet().size();
    }

    @Override public boolean containsKey(Object key) {
      return backingSet().contains(key);
    }

    @Override public V get(Object key) {
      if (backingSet().contains(key)) {
        @SuppressWarnings("unchecked") // unsafe, but Javadoc warns about it
            K k = (K) key;
        return function.apply(k);
      } else {
        return null;
      }
    }

    @Override public V remove(Object key) {
      if (backingSet().remove(key)) {
        @SuppressWarnings("unchecked") // unsafe, but Javadoc warns about it
            K k = (K) key;
        return function.apply(k);
      } else {
        return null;
      }
    }

    @Override public void clear() {
      backingSet().clear();
    }

    @Override protected Set> createEntrySet() {
      return new EntrySet() {
        @Override Map map() {
          return AsMapView.this;
        }

        @Override public Iterator> iterator() {
          return asSetEntryIterator(backingSet(), function);
        }
      };
    }
  }

  /** EntrySet.
   *
   * @param  key type
   * @param  value type */
  abstract static class EntrySet
      extends ImprovedAbstractSet> {
    abstract Map map();

    @Override public int size() {
      return map().size();
    }

    @Override public void clear() {
      map().clear();
    }

    @Override public boolean contains(Object o) {
      if (o instanceof Map.Entry) {
        Map.Entry entry = (Map.Entry) o;
        Object key = entry.getKey();
        V value = map().get(key);
        return Objects.equals(value, entry.getValue())
            && (value != null || map().containsKey(key));
      }
      return false;
    }

    @Override public boolean isEmpty() {
      return map().isEmpty();
    }

    @Override public boolean remove(Object o) {
      if (contains(o)) {
        Map.Entry entry = (Map.Entry) o;
        return map().keySet().remove(entry.getKey());
      }
      return false;
    }

    @Override public boolean removeAll(Collection c) {
      try {
        return super.removeAll(Objects.requireNonNull(c));
      } catch (UnsupportedOperationException e) {
        // if the iterators don't support remove
        boolean changed = true;
        for (Object o : c) {
          changed |= remove(o);
        }
        return changed;
      }
    }

    @Override public boolean retainAll(Collection c) {
      try {
        return super.retainAll(Objects.requireNonNull(c));
      } catch (UnsupportedOperationException e) {
        // if the iterators don't support remove
        Set keys = Sets.newHashSetWithExpectedSize(c.size());
        for (Object o : c) {
          if (contains(o)) {
            Map.Entry entry = (Map.Entry) o;
            keys.add(entry.getKey());
          }
        }
        return map().keySet().retainAll(keys);
      }
    }
  }

  static  Iterator valueIterator(
      Iterator> entryIterator) {
    return new TransformedIterator, V>(entryIterator) {
      @Override V transform(Map.Entry entry) {
        return entry.getValue();
      }
    };
  }

  /** Values.
   *
   * @param  key type
   * @param  value type */
  abstract static class Values extends AbstractCollection {
    abstract Map map();

    @Override public Iterator iterator() {
      return valueIterator(map().entrySet().iterator());
    }

    @Override public boolean remove(Object o) {
      try {
        return super.remove(o);
      } catch (UnsupportedOperationException e) {
        for (Map.Entry entry : map().entrySet()) {
          if (Objects.equals(o, entry.getValue())) {
            map().remove(entry.getKey());
            return true;
          }
        }
        return false;
      }
    }

    @Override public boolean removeAll(Collection c) {
      try {
        return super.removeAll(Objects.requireNonNull(c));
      } catch (UnsupportedOperationException e) {
        Set toRemove = new HashSet<>();
        for (Map.Entry entry : map().entrySet()) {
          if (c.contains(entry.getValue())) {
            toRemove.add(entry.getKey());
          }
        }
        return map().keySet().removeAll(toRemove);
      }
    }

    @Override public boolean retainAll(Collection c) {
      try {
        return super.retainAll(Objects.requireNonNull(c));
      } catch (UnsupportedOperationException e) {
        Set toRetain = new HashSet<>();
        for (Map.Entry entry : map().entrySet()) {
          if (c.contains(entry.getValue())) {
            toRetain.add(entry.getKey());
          }
        }
        return map().keySet().retainAll(toRetain);
      }
    }

    @Override public int size() {
      return map().size();
    }

    @Override public boolean isEmpty() {
      return map().isEmpty();
    }

    @Override public boolean contains(Object o) {
      return map().containsValue(o);
    }

    @Override public void clear() {
      map().clear();
    }
  }

  /** TransformedIterator.
   *
   * @param  from type
   * @param  to type */
  abstract static class TransformedIterator implements Iterator {
    final Iterator backingIterator;

    TransformedIterator(Iterator backingIterator) {
      this.backingIterator = Objects.requireNonNull(backingIterator);
    }

    abstract T transform(F from);

    public final boolean hasNext() {
      return backingIterator.hasNext();
    }

    public final T next() {
      return transform(backingIterator.next());
    }

    public final void remove() {
      backingIterator.remove();
    }
  }

  /** Implements {@link Compatible#navigableSet}. */
  static  NavigableSet navigableSet(ImmutableSortedSet set) {
    if (set instanceof NavigableSet) {
      // In Guava 12 and later, ImmutableSortedSet implements NavigableSet.
      //noinspection unchecked
      return (NavigableSet) set;
    } else {
      // In Guava 11, we have to make a copy.
      return new TreeSet(set);
    }
  }

  /** Implements {@link Compatible#navigableMap}. */
  static  NavigableMap navigableMap(ImmutableSortedMap map) {
    if (map instanceof NavigableMap) {
      // In Guava 12 and later, ImmutableSortedMap implements NavigableMap.
      //noinspection unchecked
      return (NavigableMap) map;
    } else {
      // In Guava 11, we have to make a copy.
      return new TreeMap(map);
    }
  }
}

// End CompatibleGuava11.java