/* * Copyright 2003-2014 JetBrains s.r.o. * * 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 jetbrains.mps.util; import jetbrains.mps.util.iterable.DistinctIterator; import jetbrains.mps.util.iterable.MergeIterator; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; public class IterableUtil { @NotNull public static <T> Iterable<T> distinct(@Nullable Iterable<T> t) { if (t == null) { return Collections.emptyList(); } return new DistinctIterator<T>(t); } @NotNull public static <T> Iterable<T> merge(@NotNull Iterable<T>... its) { List<Iterable<T>> toMerge = asList(CollectionUtil.withoutNulls(Arrays.asList(its))); if (toMerge.size() == 0) { return Collections.emptyList(); } else if (toMerge.size() == 1) { return toMerge.get(0); } else if (toMerge.size() == 2) { return new MergeIterator<T>(toMerge.get(0), toMerge.get(1)); } return new FlattenIterable<T>(toMerge); } /** * FIXME: conversion of wildcard type to its upper bound breaks container's contract * Example: * <code> * <p> * class A {}; * class B extends A {} * <p> * Set<B> sob = new HashSet<B>(); * <p> * Iterable<? extends A> ioa = sob; * <p> * Set<A> soa = IterableUtil.asSet(ioa); * soa.add(new A()); * <p> * B b = sob.iterator().next(); // ClassCastException * <p> * </code> */ @NotNull public static <T> Set<T> asSet(@Nullable Iterable<? extends T> iter) { if (iter instanceof Set) { return (Set<T>) iter; } if (iter == null) { return Collections.emptySet(); } Set<T> result = new HashSet<T>(); for (T o : iter) { result.add(o); } return result; } /** * FIXME: conversion of wildcard type to its upper bound breaks container's contract * See {@code IterableUtil.asSet()} */ @NotNull public static <T> Collection<T> asCollection(@Nullable Iterable<? extends T> iter) { if (iter instanceof Collection) { return (Collection<T>) iter; } return asList(iter); } /** * FIXME: conversion of wildcard type to its upper bound breaks container's contract * See {@code IterableUtil.asSet()} */ @NotNull public static <T> List<T> asList(@Nullable Iterable<? extends T> iter) { if (iter instanceof List) { return (List<T>) iter; } return copyToList(iter); } @NotNull public static <T> List<T> copyToList(@Nullable Iterable<? extends T> iter) { if (iter == null) { return Collections.emptyList(); } List<T> result = new ArrayList<T>(); for (T o : iter) { result.add(o); } return result; } /** * FIXME: as there is no way to reset the iterator, the returned Iterable can only be iterated once */ @NotNull public static <T> Iterable<T> asIterable(@Nullable final Iterator<T> it) { if (it == null) { return Collections.emptyList(); } return new Iterable<T>() { @Override public Iterator<T> iterator() { return it; } }; } public static <T> T get(@Nullable Iterable<? extends T> data, int index) { if (data == null) { throw new IndexOutOfBoundsException(); } Iterator<? extends T> it = data.iterator(); for (int i = 0; i < index; i++) { it.next(); } return it.next(); } public static <T> int indexOf(Iterable<? extends T> data, T element) { if (data == null) { return -1; } int index = 0; for (T next : data) { if (next.equals(element)) { return index; } index++; } return -1; } }