/** * Copyright (C) 2013-2014 Olaf Lessenich * Copyright (C) 2014-2015 University of Passau, Germany * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301 USA * * Contributors: * Olaf Lessenich <lessenic@fim.uni-passau.de> * Georg Seibt <seibt@fim.uni-passau.de> */ package de.fosd.jdime.matcher.cost_model; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import de.fosd.jdime.artifact.Artifact; import de.fosd.jdime.artifact.Artifacts; /** * A list of <code>CMMatching</code>s that additionally contains the roots of the left and right trees that * are being matched. * * @param <T> * the type of the <code>Artifact</code>s */ final class CMMatchings<T extends Artifact<T>> extends ArrayList<CMMatching<T>> { T left; T right; /** * See {@link super#ArrayList(int)}. * * @param left * the left root * @param right * the right root */ public CMMatchings(int initialCapacity, T left, T right) { super(initialCapacity); this.left = left; this.right = right; } /** * See {@link super#ArrayList()}. * * @param left * the left root * @param right * the right root */ public CMMatchings(T left, T right) { this.left = left; this.right = right; } /** * See {@link super#ArrayList(Collection)}. * * @param left * the left root * @param right * the right root */ public CMMatchings(Collection<? extends CMMatching<T>> c, T left, T right) { super(c); this.left = left; this.right = right; } /** * Checks whether matchings conform to the format required by * {@link CostModelMatcher#cost(CMMatchings, CMParameters)}. That is whether there is exactly * one matching for every artifact in the left and right tree matching that artifact to one from the opposite tree * (or null). No matchings containing artifacts that do not occur in the left or right tree are tolerated. * * @return whether this <code>CMMatchings</code> has a valid format */ boolean sane() { Set<T> leftTree = new HashSet<>(Artifacts.dfs(left)); Set<T> rightTree = new HashSet<>(Artifacts.dfs(right)); if (left.getTreeSize() != leftTree.size() || right.getTreeSize() != rightTree.size()) { return false; } for (CMMatching<T> matching : this) { if (matching.m != null && !leftTree.remove(matching.m)) { return false; } if (matching.n != null && !rightTree.remove(matching.n)) { return false; } } return leftTree.isEmpty() && rightTree.isEmpty(); } /** * Returns this list of matchings as a <code>Map</code>. The map will contain matchings (l => r) and (r => l) for * every matching [l, r]. * * @return the matchings as a map */ Map<T, T> asMap() { return stream().filter(m -> !m.isNoMatch()).collect(HashMap::new, (map, matching) -> { map.put(matching.m, matching.n); map.put(matching.n, matching.m); }, HashMap::putAll); } }