org.apache.calcite.util.CompatibleGuava11.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.calcite.util.CompatibleGuava11.java

Source

/*
 * 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.base.Objects;
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.Iterator;
import java.util.Map;
import java.util.NavigableMap;
import java.util.NavigableSet;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;

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

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

    public static <K, V> Map<K, V> asMap(Set<K> set, Function<? super K, V> function) {
        return new AsMapView<K, V>(set, function);
    }

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

        @Override
        public boolean retainAll(Collection<?> c) {
            return super.retainAll(checkNotNull(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) {
        checkNotNull(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. */
    abstract static class ImprovedAbstractMap<K, V> extends AbstractMap<K, V> {
        /**
         * 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<Entry<K, V>> createEntrySet();

        private Set<Entry<K, V>> entrySet;

        @Override
        public Set<Entry<K, V>> entrySet() {
            Set<Entry<K, V>> result = entrySet;
            if (result == null) {
                entrySet = result = createEntrySet();
            }
            return result;
        }

        private Set<K> keySet;

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

        private Collection<V> values;

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

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

    /** KeySet. */
    abstract static class KeySet<K, V> extends ImprovedAbstractSet<K> {
        abstract Map<K, V> map();

        @Override
        public Iterator<K> 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 <E> Set<E> removeOnlySet(final Set<E> set) {
        return new ForwardingSet<E>() {
            @Override
            protected Set<E> delegate() {
                return set;
            }

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

            @Override
            public boolean addAll(Collection<? extends E> es) {
                throw new UnsupportedOperationException();
            }
        };
    }

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

    /** AsMapView. */
    private static class AsMapView<K, V> extends ImprovedAbstractMap<K, V> {
        private final Set<K> set;
        final Function<? super K, V> function;

        Set<K> backingSet() {
            return set;
        }

        AsMapView(Set<K> set, Function<? super K, V> function) {
            this.set = checkNotNull(set);
            this.function = checkNotNull(function);
        }

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

        @Override
        public Collection<V> 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<Map.Entry<K, V>> createEntrySet() {
            return new EntrySet<K, V>() {
                @Override
                Map<K, V> map() {
                    return AsMapView.this;
                }

                @Override
                public Iterator<Map.Entry<K, V>> iterator() {
                    return asSetEntryIterator(backingSet(), function);
                }
            };
        }
    }

    /** EntrySet. */
    abstract static class EntrySet<K, V> extends ImprovedAbstractSet<Map.Entry<K, V>> {
        abstract Map<K, V> 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.equal(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(checkNotNull(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(checkNotNull(c));
            } catch (UnsupportedOperationException e) {
                // if the iterators don't support remove
                Set<Object> 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 <K, V> Iterator<V> valueIterator(Iterator<Map.Entry<K, V>> entryIterator) {
        return new TransformedIterator<Map.Entry<K, V>, V>(entryIterator) {
            @Override
            V transform(Map.Entry<K, V> entry) {
                return entry.getValue();
            }
        };
    }

    /** Values. */
    abstract static class Values<K, V> extends AbstractCollection<V> {
        abstract Map<K, V> map();

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

        @Override
        public boolean remove(Object o) {
            try {
                return super.remove(o);
            } catch (UnsupportedOperationException e) {
                for (Map.Entry<K, V> entry : map().entrySet()) {
                    if (com.google.common.base.Objects.equal(o, entry.getValue())) {
                        map().remove(entry.getKey());
                        return true;
                    }
                }
                return false;
            }
        }

        @Override
        public boolean removeAll(Collection<?> c) {
            try {
                return super.removeAll(checkNotNull(c));
            } catch (UnsupportedOperationException e) {
                Set<K> toRemove = Sets.newHashSet();
                for (Map.Entry<K, V> 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(checkNotNull(c));
            } catch (UnsupportedOperationException e) {
                Set<K> toRetain = Sets.newHashSet();
                for (Map.Entry<K, V> 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. */
    abstract static class TransformedIterator<F, T> implements Iterator<T> {
        final Iterator<? extends F> backingIterator;

        TransformedIterator(Iterator<? extends F> backingIterator) {
            this.backingIterator = checkNotNull(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 <E> NavigableSet<E> navigableSet(ImmutableSortedSet<E> 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<E>(set);
        }
    }

    /** Implements {@link Compatible#navigableMap}. */
    static <K, V> NavigableMap<K, V> navigableMap(ImmutableSortedMap<K, V> 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<K, V>(map);
        }
    }
}

// End CompatibleGuava11.java