1/*2 * Licensed to the Apache Software Foundation (ASF) under one3 * or more contributor license agreements. See the NOTICE file4 * distributed with this work for additional information5 * regarding copyright ownership. The ASF licenses this file6 * to you under the Apache License, Version 2.0 (the7 * "License"); you may not use this file except in compliance8 * with the License. You may obtain a copy of the License at9 *10 * http://www.apache.org/licenses/LICENSE-2.011 *12 * Unless required by applicable law or agreed to in writing, software13 * 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 and16 * limitations under the License.17 */1819package org.apache.giraph.utils;
2021import com.google.common.collect.Iterables;
22import java.util.Collection;
23import java.util.Iterator;
24import java.util.concurrent.ConcurrentMap;
25import org.apache.log4j.Logger;
2627/** Helper methods for Collections */28publicclassCollectionUtils {
29/** Class logger */30privatestaticfinal Logger LOG = Logger.getLogger(CollectionUtils.class);
3132/** Do not instantiate. */33privateCollectionUtils() { }
3435/**36 * If map already has a value associated with the key it adds values to that37 * value, otherwise it will put values to the map. Do not reuse values.38 *39 * @param key Key under which we are adding values40 * @param values Values we want to add41 * @param map Map which we are adding values to42 * @param <K> Key43 * @param <V> Value44 * @param <C> Collection45 * @return New value associated with the key46 */47publicstatic <K, V, C extends Collection<V>> C addConcurrent(K key,
48 C values, ConcurrentMap<K, C> map) {
49 C currentValues = map.get(key);
50if (currentValues == null) {
51 currentValues = map.putIfAbsent(key, values);
52if (currentValues == null) {
53return values;
54 }
55 }
56synchronized (currentValues) {
57 currentValues.addAll(values);
58 }
59return currentValues;
60 }
6162/**63 * Helper method to check if iterables are equal. Supports the case64 * where the iterable next() returns a reused object. We do assume that65 * 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 should67 * be used for testing only.68 *69 * @param first First iterable70 * @param second Second iterable71 * @param <T> Type to compare72 * @return True if equal, false otherwise73 */74publicstatic <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 by77// marking the ones seen that have been found. Then ensure that all78// the elements of the second have been seen as well.79int firstSize = Iterables.size(first);
80int secondSize = Iterables.size(second);
81boolean[] usedSecondArray = newboolean[secondSize];
82 Iterator<T> firstIterator = first.iterator();
83while (firstIterator.hasNext()) {
84 T firstValue = firstIterator.next();
85boolean foundFirstValue = false;
86 Iterator<T> secondIterator = second.iterator();
87for (int i = 0; i < usedSecondArray.length; ++i) {
88 T secondValue = secondIterator.next();
89if (!usedSecondArray[i]) {
90if (firstValue.equals(secondValue)) {
91 usedSecondArray[i] = true;
92 foundFirstValue = true;
93break;
94 }
95 }
96 }
9798if (!foundFirstValue) {
99 LOG.error("isEqual: Couldn't find element from first (" + firstValue +
100") in second " + second + "(size=" + secondSize + ")");
101return false;
102 }
103 }
104105 Iterator<T> secondIterator = second.iterator();
106for (int i = 0; i < usedSecondArray.length; ++i) {
107 T secondValue = secondIterator.next();
108if (!usedSecondArray[i]) {
109 LOG.error("isEqual: Element " + secondValue + " (index " + i +
110") in second " + second + "(size=" + secondSize +
111") not found in " + first + " (size=" + firstSize + ")");
112return false;
113 }
114 }
115116returntrue;
117 }
118 }