de.cuioss.tools.collect.MapDiffenceImpl Maven / Gradle / Ivy
Show all versions of cui-java-tools Show documentation
/*
* Copyright 2023 the original author or authors.
*
* 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
*
* https://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 de.cuioss.tools.collect;
import static java.util.Objects.requireNonNull;
import java.util.Map;
import java.util.Map.Entry;
import de.cuioss.tools.collect.MapDifference.ValueDifference;
import lombok.EqualsAndHashCode;
import lombok.RequiredArgsConstructor;
import lombok.ToString;
/**
* @author Oliver Wolff
*
*/
@RequiredArgsConstructor
@EqualsAndHashCode
@ToString
class MapDiffenceImpl implements MapDifference {
private final Map entriesOnlyOnRight;
private final Map entriesOnlyOnLeft;
private final Map entriesInCommon;
private final Map> entriesDiffering;
@Override
public boolean areEqual() {
return entriesOnlyOnLeft.isEmpty() && entriesOnlyOnRight.isEmpty() && entriesDiffering.isEmpty();
}
@Override
public Map entriesOnlyOnLeft() {
return entriesOnlyOnLeft;
}
@Override
public Map entriesOnlyOnRight() {
return entriesOnlyOnRight;
}
@Override
public Map entriesInCommon() {
return entriesInCommon;
}
@Override
public Map> entriesDiffering() {
return entriesDiffering;
}
/**
* Computes the difference between two maps. This difference is an immutable
* snapshot of the state of the maps at the time this method is called. It will
* never change, even if the maps change at a later time.
*
*
* Since this method uses {@code HashMap} instances internally, the keys of the
* supplied maps must be well-behaved with respect to {@link Object#equals} and
* {@link Object#hashCode}.
*
*
* Note:If you only need to know whether two maps have the same mappings,
* call {@code
* left.equals(right)} instead of this method.
*
* @param left the map to treat as the "left" map for purposes of comparison
* @param right the map to treat as the "right" map for purposes of comparison
* @return the difference between the two maps
*
* @author com.google.common.collect.MapDifference
*/
static MapDifference from(Map extends K, ? extends V> left, Map extends K, ? extends V> right) {
requireNonNull(left);
requireNonNull(right);
var onlyRight = new MapBuilder();
var onlyLeft = new MapBuilder();
var common = new MapBuilder();
var entriesDiffering = new MapBuilder>();
sortEntriesToBucket(left, right, onlyLeft, common, entriesDiffering);
// now from the other direction.
sortEntriesToBucket(right, left, onlyRight, common, entriesDiffering);
return new MapDiffenceImpl<>(onlyRight.toImmutableMap(), onlyLeft.toImmutableMap(), common.toImmutableMap(),
entriesDiffering.toImmutableMap());
}
static void sortEntriesToBucket(Map extends K, ? extends V> left, Map extends K, ? extends V> right,
MapBuilder onlyLeft, MapBuilder common, MapBuilder> entriesDiffering) {
for (Entry extends K, ? extends V> entry : left.entrySet()) {
if (right.containsKey(entry.getKey())) {
V rightValue = right.get(entry.getKey());
V leftValue = entry.getValue();
if (checkEqualityNullsafe(leftValue, rightValue)) {
// Ensure not adding again for the second run
if (!common.containsKey(entry.getKey())) {
common.put(entry);
}
// Ensure not adding again for the second run
} else if (!entriesDiffering.containsKey(entry.getKey())) {
entriesDiffering.put(entry.getKey(), new ValueDifferenceImpl<>(leftValue, rightValue));
}
} else {
onlyLeft.put(entry);
}
}
}
private static boolean checkEqualityNullsafe(Object leftValue, Object rightValue) {
if (leftValue == rightValue) {
return true;
}
if (null == leftValue || null == rightValue) {
return false;
}
return leftValue.equals(rightValue);
}
}
@RequiredArgsConstructor
class ValueDifferenceImpl implements ValueDifference {
private final V leftValue;
/** Returns the value from the right map (possibly null). */
private final V rightValue;
@Override
public V leftValue() {
return leftValue;
}
@Override
public V rightValue() {
return rightValue;
}
}