/* * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code 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 General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package selectionresolution; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Set; import java.util.Map; /** * A representation of a class/interface hierarchy graph (just the * graph; the class data is represented elsewhere). */ public class HierarchyShape { public static final int OBJECT_CLASS = -1; protected int maxId; /** * The names of all the classes. */ private final HashSet<Integer> classes; /** * The names of all the interfaces. */ private final HashSet<Integer> interfaces; private final HashMap<Integer, HashSet<Integer>> extensions; /** * Create an empty hierarchy shape. */ public HierarchyShape() { this(0, new HashSet<>(), new HashSet<>(), new HashMap<>()); } private HierarchyShape(final int maxId, final HashSet<Integer> classes, final HashSet<Integer> interfaces, final HashMap<Integer, HashSet<Integer>> extensions) { this.maxId = maxId; this.classes = classes; this.interfaces = interfaces; this.extensions = extensions; } /** * Make a copy of this hierarchy shape. */ public HierarchyShape copy() { final HashMap<Integer, HashSet<Integer>> newextensions = new HashMap<>(); for(final Map.Entry<Integer, HashSet<Integer>> entry : extensions.entrySet()) { newextensions.put(entry.getKey(), (HashSet<Integer>)entry.getValue().clone()); } return new HierarchyShape(maxId, (HashSet<Integer>) classes.clone(), (HashSet<Integer>) interfaces.clone(), newextensions); } /** * Add a class, and return its id. * * @return The new class id. */ public int addClass() { final int id = maxId++; classes.add(id); return id; } /** * Add an interface, and return its id. * * @return The new interface id. */ public int addInterface() { final int id = maxId++; interfaces.add(id); return id; } /** * Add an inheritance. * * @param sub The sub class/interface. * @param sup The super class/interface */ public void addInherit(final int sub, final int sup) { HashSet<Integer> ext = extensions.get(sub); if (ext == null) { ext = new HashSet<>(); extensions.put(sub, ext); } ext.add(sup); } @Override public String toString() { String out = ""; for(int i = maxId - 1; i >= 0; i--) { out += i + ": "; for(int j = 0; j < maxId; j++) { out += "[" + (inherits(i, j) ? "1" : "0") + "]"; } out += "\n"; } return out; } /** * Indicate whether the first class inherits from the second. * * @param sub The possible subtype. * @param sup The possible supertype. * @return Whether or not {@code sub} inherits from {@code sup}. */ public boolean inherits(final int sub, final int sup) { final Set<Integer> ext = extensions.get(sub); if (ext != null) { return ext.contains(sup); } else { return false; } } /** * Indicate whether a given type name is a class. * * @param id The type in question. * @return Whether or not the type is a class. */ public boolean isClass(final int id) { if (id == OBJECT_CLASS) { return true; } return classes.contains(id); } /** * Indicate whether a given type name is an interface. * * @param id The type in question. * @return Whether or not the type is an interface. */ public boolean isInterface(final int id) { if (id == OBJECT_CLASS) { return false; } return interfaces.contains(id); } /** * Get an iterator over the classes. * * @return An iterator over classes. */ public Collection<Integer> classes() { return classes; } /** * Get an iterator over the interfaces. * * @return An iterator over interfaces. */ public Collection<Integer> interfaces() { return interfaces; } /** * Get an iterator over all types. * * @return An iterator over all types. */ public Collection<Integer> types() { final Set<Integer> combined = new HashSet(classes); combined.addAll(interfaces); return combined; } public int numClasses() { return classes.size(); } public int numInterfaces() { return interfaces.size(); } public int numTypes() { return numClasses() + numInterfaces(); } }