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

org.gradle.util.CollectionUtils Maven / Gradle / Ivy

There is a newer version: 8.6
Show newest version
/*
 * Copyright 2011 the original author or 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 org.gradle.util;

import com.google.common.base.Joiner;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import org.gradle.api.Action;
import org.gradle.api.Transformer;
import org.gradle.api.specs.Spec;
import org.gradle.internal.Factory;
import org.gradle.internal.Pair;
import org.gradle.internal.Transformers;

import javax.annotation.Nullable;
import java.lang.reflect.Array;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;

import static org.gradle.internal.Cast.cast;
import static org.gradle.internal.Cast.castNullable;
import static org.gradle.internal.Cast.uncheckedNonnullCast;

public abstract class CollectionUtils {

    /**
     * Returns null if the collection is empty otherwise expects a {@link #single(Iterable)} element to be found.
     */
    @Nullable
    public static  T findSingle(Iterable source) {
        return Iterables.isEmpty(source) ? null : single(source);
    }

    /**
     * Returns the single element in the collection or throws.
     */
    public static  T single(Iterable source) {
        Iterator iterator = source.iterator();
        if (!iterator.hasNext()) {
            throw new NoSuchElementException("Expecting collection with single element, got none.");
        }
        T element = iterator.next();
        if (iterator.hasNext()) {
            throw new IllegalArgumentException("Expecting collection with single element, got multiple.");
        }
        return element;
    }

    public static  Collection checkedCast(Class type, Collection input) {
        for (Object o : input) {
            castNullable(type, o);
        }
        return uncheckedNonnullCast(input);
    }

    @Nullable
    public static  T findFirst(Iterable source, Spec filter) {
        for (T item : source) {
            if (filter.isSatisfiedBy(item)) {
                return item;
            }
        }

        return null;
    }

    @Nullable
    public static  T findFirst(T[] source, Spec filter) {
        for (T thing : source) {
            if (filter.isSatisfiedBy(thing)) {
                return thing;
            }
        }

        return null;
    }

    public static  T first(Iterable source) {
        return source.iterator().next();
    }

    public static  boolean any(Iterable source, Spec filter) {
        return findFirst(source, filter) != null;
    }

    public static  boolean any(T[] source, Spec filter) {
        return findFirst(source, filter) != null;
    }

    public static  Set filter(Set set, Spec filter) {
        return filter(set, new LinkedHashSet(), filter);
    }

    public static  List filter(List list, Spec filter) {
        return filter(list, Lists.newArrayListWithCapacity(list.size()), filter);
    }

    public static  List filter(T[] array, Spec filter) {
        return filter(Arrays.asList(array), Lists.newArrayListWithCapacity(array.length), filter);
    }


    /**
     * Returns a sorted copy of the provided collection of things. Uses the provided comparator to sort.
     */
    public static  List sort(Iterable things, Comparator comparator) {
        List copy = toMutableList(things);
        Collections.sort(copy, comparator);
        return copy;
    }

    /**
     * Returns a sorted copy of the provided collection of things. Uses the natural ordering of the things.
     */
    public static > List sort(Iterable things) {
        List copy = toMutableList(things);
        Collections.sort(copy);
        return copy;
    }

    public static > C filter(Iterable source, C destination, Spec filter) {
        for (T item : source) {
            if (filter.isSatisfiedBy(item)) {
                destination.add(item);
            }
        }
        return destination;
    }

    public static  Map filter(Map map, Spec> filter) {
        return filter(map, new HashMap(), filter);
    }

    public static  Map filter(Map map, Map destination, Spec> filter) {
        for (Map.Entry entry : map.entrySet()) {
            if (filter.isSatisfiedBy(entry)) {
                destination.put(entry.getKey(), entry.getValue());
            }
        }

        return destination;
    }

    public static  R[] collectArray(I[] list, Class newType, Transformer transformer) {
        @SuppressWarnings("unchecked") R[] destination = (R[]) Array.newInstance(newType, list.length);
        return collectArray(list, destination, transformer);
    }

    public static  R[] collectArray(I[] list, R[] destination, Transformer transformer) {
        assert list.length <= destination.length;
        for (int i = 0; i < list.length; ++i) {
            destination[i] = transformer.transform(list[i]);
        }
        return destination;
    }

    public static  List collect(I[] list, Transformer transformer) {
        return collect(Arrays.asList(list), transformer);
    }

    public static  Set collect(Set set, Transformer transformer) {
        return collect(set, new HashSet(set.size()), transformer);
    }

    public static  List collect(Iterable source, Transformer transformer) {
        if (source instanceof Collection) {
            Collection collection = uncheckedNonnullCast(source);
            return collect(source, new ArrayList(collection.size()), transformer);
        } else {
            return collect(source, new LinkedList(), transformer);
        }
    }

    public static > C collect(Iterable source, C destination, Transformer transformer) {
        for (I item : source) {
            destination.add(transformer.transform(item));
        }
        return destination;
    }

    public static List toStringList(Iterable iterable) {
        return collect(iterable, new LinkedList(), Transformers.asString());
    }

    /**
     * Recursively unpacks all the given things into a flat list.
     *
     * Nulls are not removed, they are left intact.
     *
     * @param things The things to flatten
     * @return A flattened list of the given things
     */
    public static List flattenCollections(Object... things) {
        return flattenCollections(Object.class, things);
    }

    /**
     * Recursively unpacks all the given things into a flat list, ensuring they are of a certain type.
     *
     * Nulls are not removed, they are left intact.
     *
     * If a non null object cannot be cast to the target type, a ClassCastException will be thrown.
     *
     * @param things The things to flatten
     * @param  The target type in the flattened list
     * @return A flattened list of the given things
     */
    public static  List flattenCollections(Class type, Object... things) {
        if (things == null) {
            return Collections.singletonList(null);
        } else if (things.length == 0) {
            return Collections.emptyList();
        } else if (things.length == 1) {
            Object thing = things[0];

            if (thing == null) {
                return Collections.singletonList(null);
            }

            // Casts to Class below are to workaround Eclipse compiler bug
            // See: https://github.com/gradle/gradle/pull/200

            if (thing.getClass().isArray()) {
                Object[] thingArray = (Object[]) thing;
                List list = new ArrayList(thingArray.length);
                for (Object thingThing : thingArray) {
                    list.addAll(flattenCollections(type, thingThing));
                }
                return list;
            }

            if (thing instanceof Collection) {
                Collection collection = (Collection) thing;
                List list = new ArrayList();
                for (Object element : collection) {
                    list.addAll(flattenCollections(type, element));
                }
                return list;
            }

            return Collections.singletonList(cast(type, thing));
        } else {
            List list = new ArrayList();
            for (Object thing : things) {
                list.addAll(flattenCollections(type, thing));
            }
            return list;
        }
    }

    public static  List toList(Iterable things) {
        if (things instanceof List) {
            @SuppressWarnings("unchecked") List castThings = (List) things;
            return castThings;
        }
        return toMutableList(things);
    }

    public static  List toList(Enumeration things) {
        AbstractList list = new ArrayList();
        while (things.hasMoreElements()) {
            list.add(things.nextElement());
        }
        return list;
    }

    private static  List toMutableList(Iterable things) {
        if (things == null) {
            return new ArrayList(0);
        }
        List list = new ArrayList();
        for (T thing : things) {
            list.add(thing);
        }
        return list;
    }


    public static  List intersection(Collection> availableValuesByDescriptor) {
        List result = new ArrayList();
        Iterator> iterator = availableValuesByDescriptor.iterator();
        if (iterator.hasNext()) {
            Collection firstSet = iterator.next();
            result.addAll(firstSet);
            while (iterator.hasNext()) {
                Collection next = iterator.next();
                result.retainAll(next);
            }
        }
        return result;

    }

    public static  List toList(T[] things) {
        if (things == null || things.length == 0) {
            return new ArrayList(0);
        }

        List list = new ArrayList(things.length);
        Collections.addAll(list, things);
        return list;
    }

    public static  Set toSet(Iterable things) {
        if (things == null) {
            return new HashSet(0);
        }
        if (things instanceof Set) {
            @SuppressWarnings("unchecked") Set castThings = (Set) things;
            return castThings;
        }

        Set set = new LinkedHashSet();
        for (T thing : things) {
            set.add(thing);
        }
        return set;
    }

    public static  List compact(List list) {
        boolean foundAtLeastOneNull = false;
        List compacted = null;
        int i = 0;

        for (E element : list) {
            if (element == null) {
                if (!foundAtLeastOneNull) {
                    compacted = new ArrayList(list.size());
                    if (i > 0) {
                        compacted.addAll(list.subList(0, i));
                    }
                }
                foundAtLeastOneNull = true;
            } else if (foundAtLeastOneNull) {
                compacted.add(element);
            }
            ++i;
        }

        return foundAtLeastOneNull ? compacted : list;
    }

    public static > C stringize(Iterable source, C destination) {
        return collect(source, destination, Transformers.asString());
    }

    public static List stringize(Collection source) {
        return stringize(source, new ArrayList(source.size()));
    }

    public static  boolean replace(List list, Spec filter, Transformer transformer) {
        boolean replaced = false;
        int i = 0;
        for (E it : list) {
            if (filter.isSatisfiedBy(it)) {
                list.set(i, transformer.transform(it));
                replaced = true;
            }
            ++i;
        }
        return replaced;
    }

    public static  void collectMap(Map destination, Iterable items, Transformer keyGenerator) {
        for (V item : items) {
            destination.put(keyGenerator.transform(item), item);
        }
    }

    /**
     * Given a set of values, derive a set of keys and return a map
     */
    public static  Map collectMap(Iterable items, Transformer keyGenerator) {
        Map map = new LinkedHashMap();
        collectMap(map, items, keyGenerator);
        return map;
    }

    public static  void collectMapValues(Map destination, Iterable keys, Transformer keyGenerator) {
        for (K item : keys) {
            destination.put(item, keyGenerator.transform(item));
        }
    }

    /**
     * Given a set of keys, derive a set of values and return a map
     */
    public static  Map collectMapValues(Iterable keys, Transformer keyGenerator) {
        Map map = new LinkedHashMap();
        collectMapValues(map, keys, keyGenerator);
        return map;
    }

    public static  boolean every(Iterable things, Spec predicate) {
        for (T thing : things) {
            if (!predicate.isSatisfiedBy(thing)) {
                return false;
            }
        }

        return true;
    }

    /**
     * Utility for adding an iterable to a collection.
     *
     * @param t1 The collection to add to
     * @param t2 The iterable to add each item of to the collection
     * @param  The element type of t1
     * @return t1
     */
    public static > C addAll(C t1, Iterable t2) {
        for (T t : t2) {
            t1.add(t);
        }
        return t1;
    }

    /**
     * Utility for adding an array to a collection.
     *
     * @param t1 The collection to add to
     * @param t2 The iterable to add each item of to the collection
     * @param  The element type of t1
     * @return t1
     */
    public static > C addAll(C t1, T... t2) {
        Collections.addAll(t1, t2);
        return t1;
    }

    /**
     * The result of diffing two sets.
     *
     * @param  The type of element the sets contain
     * @see CollectionUtils#diffSetsBy(java.util.Set, java.util.Set, org.gradle.api.Transformer)
     */
    public static class SetDiff {
        public Set leftOnly = new HashSet();
        public Set> common = new HashSet>();
        public Set rightOnly = new HashSet();
    }

    /**
     * Provides a “diff report” of how the two sets are similar and how they are different, comparing the entries by some aspect.
     *
     * The transformer is used to generate the value to use to compare the entries by. That is, the entries are not compared by equals by an attribute or characteristic.
     *
     * The transformer is expected to produce a unique value for each entry in a single set. Behaviour is undefined if this condition is not met.
     *
     * @param left The set on the “left” side of the comparison.
     * @param right The set on the “right” side of the comparison.
     * @param compareBy Provides the value to compare entries from either side by
     * @param  The type of the entry objects
     * @return A representation of the difference
     */
    public static  SetDiff diffSetsBy(Set left, Set right, Transformer compareBy) {
        if (left == null) {
            throw new NullPointerException("'left' set is null");
        }
        if (right == null) {
            throw new NullPointerException("'right' set is null");
        }

        SetDiff setDiff = new SetDiff();

        Map indexedLeft = collectMap(left, compareBy);
        Map indexedRight = collectMap(right, compareBy);

        for (Map.Entry leftEntry : indexedLeft.entrySet()) {
            T rightValue = indexedRight.remove(leftEntry.getKey());
            if (rightValue == null) {
                setDiff.leftOnly.add(leftEntry.getValue());
            } else {
                Pair pair = Pair.of(leftEntry.getValue(), rightValue);
                setDiff.common.add(pair);
            }
        }

        for (T rightValue : indexedRight.values()) {
            setDiff.rightOnly.add(rightValue);
        }

        return setDiff;
    }

    /**
     * Creates a string with {@code toString()} of each object with the given separator.
     *
     * 
     * expect:
     * join(",", new Object[]{"a"}) == "a"
     * join(",", new Object[]{"a", "b", "c"}) == "a,b,c"
     * join(",", new Object[]{}) == ""
     * 
* * The {@code separator} must not be null and {@code objects} must not be null. * * @param separator The string by which to join each string representation * @param objects The objects to join the string representations of * @return The joined string */ public static String join(String separator, Object[] objects) { return join(separator, objects == null ? null : Arrays.asList(objects)); } /** * Creates a string with {@code toString()} of each object with the given separator. * *
     * expect:
     * join(",", ["a"]) == "a"
     * join(",", ["a", "b", "c"]) == "a,b,c"
     * join(",", []) == ""
     * 
* * The {@code separator} must not be null and {@code objects} must not be null. * * @param separator The string by which to join each string representation * @param objects The objects to join the string representations of * @return The joined string */ public static String join(String separator, Iterable objects) { if (separator == null) { throw new NullPointerException("The 'separator' cannot be null"); } if (objects == null) { throw new NullPointerException("The 'objects' cannot be null"); } StringBuilder string = new StringBuilder(); Iterator iterator = objects.iterator(); if (iterator.hasNext()) { string.append(iterator.next().toString()); while (iterator.hasNext()) { string.append(separator); string.append(iterator.next().toString()); } } return string.toString(); } /** * Partition given Collection into a Pair of Collections. * *
Left
Collection containing entries that satisfy the given predicate *
Right
Collection containing entries that do NOT satisfy the given predicate */ public static Pair, Collection> partition(Iterable items, Spec predicate) { Preconditions.checkNotNull(items, "Cannot partition null Collection"); Preconditions.checkNotNull(predicate, "Cannot apply null Spec when partitioning"); Collection left = new LinkedList(); Collection right = new LinkedList(); for (T item : items) { if (predicate.isSatisfiedBy(item)) { left.add(item); } else { right.add(item); } } return Pair.of(left, right); } public static class InjectionStep { private final T target; private final I item; public InjectionStep(T target, I item) { this.target = target; this.item = item; } public T getTarget() { return target; } public I getItem() { return item; } } public static T inject(T target, Iterable items, Action> action) { if (target == null) { throw new NullPointerException("The 'target' cannot be null"); } if (items == null) { throw new NullPointerException("The 'items' cannot be null"); } if (action == null) { throw new NullPointerException("The 'action' cannot be null"); } for (I item : items) { action.execute(new InjectionStep(target, item)); } return target; } public static Map> groupBy(Iterable iterable, Transformer grouper) { ImmutableListMultimap.Builder builder = ImmutableListMultimap.builder(); for (V element : iterable) { K key = grouper.transform(element); builder.put(key, element); } return builder.build().asMap(); } public static Iterable unpack(final Iterable> factories) { return new Iterable() { private final Iterator> delegate = factories.iterator(); @Override public Iterator iterator() { return new Iterator() { @Override public boolean hasNext() { return delegate.hasNext(); } @Override public T next() { return delegate.next().create(); } @Override public void remove() { throw new UnsupportedOperationException(); } }; } }; } @Nullable public static List nonEmptyOrNull(Iterable iterable) { ImmutableList list = ImmutableList.copyOf(iterable); return list.isEmpty() ? null : list; } public static String asCommandLine(Iterable arguments) { return Joiner.on(" ").join(collect(arguments, Transformers.asSafeCommandLineArgument())); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy