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