1 /* 2 * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 25 package org.graalvm.util; 26 27 import java.util.ArrayList; 28 import java.util.Arrays; 29 import java.util.Collection; 30 import java.util.Collections; 31 import java.util.Iterator; 32 import java.util.List; 33 import java.util.Objects; 34 import java.util.function.Function; 35 import java.util.function.IntFunction; 36 import java.util.function.Predicate; 37 import java.util.function.Supplier; 38 39 /** 40 * This class contains utility methods for commonly used functional patterns for collections. 41 */ 42 public final class CollectionsUtil { 43 CollectionsUtil()44 private CollectionsUtil() { 45 } 46 47 /** 48 * Concatenates two iterables into a single iterable. The iterator exposed by the returned 49 * iterable does not support {@link Iterator#remove()} even if the input iterables do. 50 * 51 * @throws NullPointerException if {@code a} or {@code b} is {@code null} 52 */ concat(Iterable<T> a, Iterable<T> b)53 public static <T> Iterable<T> concat(Iterable<T> a, Iterable<T> b) { 54 List<Iterable<T>> l = Arrays.asList(a, b); 55 return concat(l); 56 } 57 58 /** 59 * Concatenates multiple iterables into a single iterable. The iterator exposed by the returned 60 * iterable does not support {@link Iterator#remove()} even if the input iterables do. 61 * 62 * @throws NullPointerException if {@code iterables} or any of its elements are {@code null} 63 */ concat(List<Iterable<T>> iterables)64 public static <T> Iterable<T> concat(List<Iterable<T>> iterables) { 65 for (Iterable<T> iterable : iterables) { 66 Objects.requireNonNull(iterable); 67 } 68 return new Iterable<T>() { 69 @Override 70 public Iterator<T> iterator() { 71 if (iterables.size() == 0) { 72 return Collections.emptyIterator(); 73 } 74 return new Iterator<T>() { 75 Iterator<Iterable<T>> cursor = iterables.iterator(); 76 Iterator<T> currentIterator = cursor.next().iterator(); 77 78 private void advance() { 79 while (!currentIterator.hasNext() && cursor.hasNext()) { 80 currentIterator = cursor.next().iterator(); 81 } 82 } 83 84 @Override 85 public boolean hasNext() { 86 advance(); 87 return currentIterator.hasNext(); 88 } 89 90 @Override 91 public T next() { 92 advance(); 93 return currentIterator.next(); 94 } 95 }; 96 } 97 98 }; 99 } 100 101 /** 102 * Returns whether all elements in {@code inputs} match {@code predicate}. May not evaluate 103 * {@code predicate} on all elements if not necessary for determining the result. If 104 * {@code inputs} is empty then {@code true} is returned and {@code predicate} is not evaluated. 105 * 106 * @return {@code true} if either all elements in {@code inputs} match {@code predicate} or 107 * {@code inputs} is empty, otherwise {@code false}. 108 */ 109 public static <T> boolean allMatch(T[] inputs, Predicate<T> predicate) { 110 return allMatch(Arrays.asList(inputs), predicate); 111 } 112 113 /** 114 * Returns whether all elements in {@code inputs} match {@code predicate}. May not evaluate 115 * {@code predicate} on all elements if not necessary for determining the result. If 116 * {@code inputs} is empty then {@code true} is returned and {@code predicate} is not evaluated. 117 * 118 * @return {@code true} if either all elements in {@code inputs} match {@code predicate} or 119 * {@code inputs} is empty, otherwise {@code false}. 120 */ 121 public static <T> boolean allMatch(Iterable<T> inputs, Predicate<T> predicate) { 122 for (T t : inputs) { 123 if (!predicate.test(t)) { 124 return false; 125 } 126 } 127 return true; 128 } 129 130 /** 131 * Returns whether any elements in {@code inputs} match {@code predicate}. May not evaluate 132 * {@code predicate} on all elements if not necessary for determining the result. If 133 * {@code inputs} is empty then {@code false} is returned and {@code predicate} is not 134 * evaluated. 135 * 136 * @return {@code true} if any elements in {@code inputs} match {@code predicate}, otherwise 137 * {@code false}. 138 */ 139 public static <T> boolean anyMatch(T[] inputs, Predicate<T> predicate) { 140 return anyMatch(Arrays.asList(inputs), predicate); 141 } 142 143 /** 144 * Returns whether any elements in {@code inputs} match {@code predicate}. May not evaluate 145 * {@code predicate} on all elements if not necessary for determining the result. If 146 * {@code inputs} is empty then {@code false} is returned and {@code predicate} is not 147 * evaluated. 148 * 149 * @return {@code true} if any elements in {@code inputs} match {@code predicate}, otherwise 150 * {@code false}. 151 */ 152 public static <T> boolean anyMatch(Iterable<T> inputs, Predicate<T> predicate) { 153 for (T t : inputs) { 154 if (predicate.test(t)) { 155 return true; 156 } 157 } 158 return false; 159 } 160 161 /** 162 * Returns a new list consisting of the elements in {@code inputs} that match {@code predicate}. 163 * 164 * @return the new list. 165 */ 166 public static <T> List<T> filterToList(List<T> inputs, Predicate<? super T> predicate) { 167 return filterToList(inputs, predicate, ArrayList::new); 168 } 169 170 /** 171 * Appends elements of {@code inputs} that match {@code predicate} to the list generated by 172 * {@code listGenerator}. 173 * 174 * @return the list generated by {@code listGenerator}. 175 */ 176 public static <T> List<T> filterToList(List<T> inputs, Predicate<? super T> predicate, Supplier<List<T>> listGenerator) { 177 List<T> resultList = listGenerator.get(); 178 for (T t : inputs) { 179 if (predicate.test(t)) { 180 resultList.add(t); 181 } 182 } 183 return resultList; 184 } 185 186 /** 187 * Filters {@code inputs} with {@code predicate}, applies {@code mapper} and adds them in the 188 * array provided by {@code arrayGenerator}. 189 * 190 * @return the array provided by {@code arrayGenerator}. 191 */ 192 public static <T, R> R[] filterAndMapToArray(T[] inputs, Predicate<? super T> predicate, Function<? super T, ? extends R> mapper, IntFunction<R[]> arrayGenerator) { 193 List<R> resultList = new ArrayList<>(); 194 for (T t : inputs) { 195 if (predicate.test(t)) { 196 resultList.add(mapper.apply(t)); 197 } 198 } 199 return resultList.toArray(arrayGenerator.apply(resultList.size())); 200 } 201 202 /** 203 * Applies {@code mapper} on the elements in {@code inputs} and adds them in the array provided 204 * by {@code arrayGenerator}. 205 * 206 * @return the array provided by {@code arrayGenerator}. 207 */ 208 public static <T, R> R[] mapToArray(T[] inputs, Function<? super T, ? extends R> mapper, IntFunction<R[]> arrayGenerator) { 209 return mapToArray(Arrays.asList(inputs), mapper, arrayGenerator); 210 } 211 212 /** 213 * Applies {@code mapper} on the elements in {@code inputs} and adds them in the array provided 214 * by {@code arrayGenerator}. 215 * 216 * @return the array provided by {@code arrayGenerator}. 217 */ 218 public static <T, R> R[] mapToArray(Collection<T> inputs, Function<? super T, ? extends R> mapper, IntFunction<R[]> arrayGenerator) { 219 R[] result = arrayGenerator.apply(inputs.size()); 220 int idx = 0; 221 for (T t : inputs) { 222 result[idx++] = mapper.apply(t); 223 } 224 return result; 225 } 226 227 /** 228 * Applies {@code mapper} on the elements in {@code inputs}, and joins them together separated 229 * by {@code delimiter}. 230 * 231 * @return a new String that is composed from {@code inputs}. 232 */ 233 public static <T, R> String mapAndJoin(T[] inputs, Function<? super T, ? extends R> mapper, String delimiter) { 234 return mapAndJoin(Arrays.asList(inputs), mapper, delimiter, "", ""); 235 } 236 237 /** 238 * Applies {@code mapper} on the elements in {@code inputs}, and joins them together separated 239 * by {@code delimiter} and starting with {@code prefix}. 240 * 241 * @return a new String that is composed from {@code inputs}. 242 */ 243 public static <T, R> String mapAndJoin(T[] inputs, Function<? super T, ? extends R> mapper, String delimiter, String prefix) { 244 return mapAndJoin(Arrays.asList(inputs), mapper, delimiter, prefix, ""); 245 } 246 247 /** 248 * Applies {@code mapper} on the elements in {@code inputs}, and joins them together separated 249 * by {@code delimiter} and starting with {@code prefix} and ending with {@code suffix}. 250 * 251 * @return a new String that is composed from {@code inputs}. 252 */ 253 public static <T, R> String mapAndJoin(T[] inputs, Function<? super T, ? extends R> mapper, String delimiter, String prefix, String suffix) { 254 return mapAndJoin(Arrays.asList(inputs), mapper, delimiter, prefix, suffix); 255 } 256 257 /** 258 * Applies {@code mapper} on the elements in {@code inputs}, and joins them together separated 259 * by {@code delimiter}. 260 * 261 * @return a new String that is composed from {@code inputs}. 262 */ 263 public static <T, R> String mapAndJoin(Iterable<T> inputs, Function<? super T, ? extends R> mapper, String delimiter) { 264 return mapAndJoin(inputs, mapper, delimiter, "", ""); 265 } 266 267 /** 268 * Applies {@code mapper} on the elements in {@code inputs}, and joins them together separated 269 * by {@code delimiter} and starting with {@code prefix}. 270 * 271 * @return a new String that is composed from {@code inputs}. 272 */ 273 public static <T, R> String mapAndJoin(Iterable<T> inputs, Function<? super T, ? extends R> mapper, String delimiter, String prefix) { 274 return mapAndJoin(inputs, mapper, delimiter, prefix, ""); 275 } 276 277 /** 278 * Applies {@code mapper} on the elements in {@code inputs}, and joins them together separated 279 * by {@code delimiter} and starting with {@code prefix} and ending with {@code suffix}. 280 * 281 * @return a new String that is composed from {@code inputs}. 282 */ 283 public static <T, R> String mapAndJoin(Iterable<T> inputs, Function<? super T, ? extends R> mapper, String delimiter, String prefix, String suffix) { 284 StringBuilder strb = new StringBuilder(); 285 String sep = ""; 286 for (T t : inputs) { 287 strb.append(sep).append(prefix).append(mapper.apply(t)).append(suffix); 288 sep = delimiter; 289 } 290 return strb.toString(); 291 } 292 293 } 294