1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19 package org.apache.giraph.utils;
20
21 import com.google.common.collect.Iterables;
22 import java.util.Collection;
23 import java.util.Iterator;
24 import java.util.concurrent.ConcurrentMap;
25 import org.apache.log4j.Logger;
26
27 /** Helper methods for Collections */
28 public class CollectionUtils {
29 /** Class logger */
30 private static final Logger LOG = Logger.getLogger(CollectionUtils.class);
31
32 /** Do not instantiate. */
33 private CollectionUtils() { }
34
35 /**
36 * If map already has a value associated with the key it adds values to that
37 * value, otherwise it will put values to the map. Do not reuse values.
38 *
39 * @param key Key under which we are adding values
40 * @param values Values we want to add
41 * @param map Map which we are adding values to
42 * @param <K> Key
43 * @param <V> Value
44 * @param <C> Collection
45 * @return New value associated with the key
46 */
47 public static <K, V, C extends Collection<V>> C addConcurrent(K key,
48 C values, ConcurrentMap<K, C> map) {
49 C currentValues = map.get(key);
50 if (currentValues == null) {
51 currentValues = map.putIfAbsent(key, values);
52 if (currentValues == null) {
53 return values;
54 }
55 }
56 synchronized (currentValues) {
57 currentValues.addAll(values);
58 }
59 return currentValues;
60 }
61
62 /**
63 * Helper method to check if iterables are equal. Supports the case
64 * where the iterable next() returns a reused object. We do assume that
65 * iterator() produces the objects in the same order across repeated calls,
66 * if the object doesn't change. This is very expensive (n^2) and should
67 * be used for testing only.
68 *
69 * @param first First iterable
70 * @param second Second iterable
71 * @param <T> Type to compare
72 * @return True if equal, false otherwise
73 */
74 public static <T> boolean isEqual(Iterable<T> first, Iterable<T> second) {
75 // Relies on elements from the iterator arriving in the same order.
76 // For every element in first, check elements on the second iterable by
77 // marking the ones seen that have been found. Then ensure that all
78 // the elements of the second have been seen as well.
79 int firstSize = Iterables.size(first);
80 int secondSize = Iterables.size(second);
81 boolean[] usedSecondArray = new boolean[secondSize];
82 Iterator<T> firstIterator = first.iterator();
83 while (firstIterator.hasNext()) {
84 T firstValue = firstIterator.next();
85 boolean foundFirstValue = false;
86 Iterator<T> secondIterator = second.iterator();
87 for (int i = 0; i < usedSecondArray.length; ++i) {
88 T secondValue = secondIterator.next();
89 if (!usedSecondArray[i]) {
90 if (firstValue.equals(secondValue)) {
91 usedSecondArray[i] = true;
92 foundFirstValue = true;
93 break;
94 }
95 }
96 }
97
98 if (!foundFirstValue) {
99 LOG.error("isEqual: Couldn't find element from first (" + firstValue +
100 ") in second " + second + "(size=" + secondSize + ")");
101 return false;
102 }
103 }
104
105 Iterator<T> secondIterator = second.iterator();
106 for (int i = 0; i < usedSecondArray.length; ++i) {
107 T secondValue = secondIterator.next();
108 if (!usedSecondArray[i]) {
109 LOG.error("isEqual: Element " + secondValue + " (index " + i +
110 ") in second " + second + "(size=" + secondSize +
111 ") not found in " + first + " (size=" + firstSize + ")");
112 return false;
113 }
114 }
115
116 return true;
117 }
118 }