1 /* 2 * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 25 import java.util.Arrays; 26 import java.util.Collection; 27 import java.util.Collections; 28 import java.util.HashMap; 29 import java.util.HashSet; 30 import java.util.NoSuchElementException; 31 import java.util.Set; 32 import java.util.Map; 33 34 /** 35 * A representation of a class/interface hierarchy graph (just the 36 * graph; the class data is represented elsewhere). 37 */ 38 public class HierarchyShape { 39 public static final int OBJECT_CLASS = -1; 40 41 protected int maxId; 42 43 /** 44 * The names of all the classes. 45 */ 46 private final HashSet<Integer> classes; 47 48 /** 49 * The names of all the interfaces. 50 */ 51 private final HashSet<Integer> interfaces; 52 private final HashMap<Integer, HashSet<Integer>> extensions; 53 54 /** 55 * Create an empty hierarchy shape. 56 */ 57 public HierarchyShape() { 58 this(0, new HashSet<>(), new HashSet<>(), new HashMap<>()); 59 } 60 61 private HierarchyShape(final int maxId, 62 final HashSet<Integer> classes, 63 final HashSet<Integer> interfaces, 64 final HashMap<Integer, HashSet<Integer>> extensions) { 65 this.maxId = maxId; 66 this.classes = classes; 67 this.interfaces = interfaces; 68 this.extensions = extensions; 69 } 70 71 /** 72 * Make a copy of this hierarchy shape. 73 */ 74 public HierarchyShape copy() { 75 final HashMap<Integer, HashSet<Integer>> newextensions = new HashMap<>(); 76 77 for(final Map.Entry<Integer, HashSet<Integer>> entry : 78 extensions.entrySet()) { 79 newextensions.put(entry.getKey(), 80 (HashSet<Integer>)entry.getValue().clone()); 81 } 82 83 return new HierarchyShape(maxId, (HashSet<Integer>) classes.clone(), 84 (HashSet<Integer>) interfaces.clone(), 85 newextensions); 86 } 87 88 /** 89 * Add a class, and return its id. 90 * 91 * @return The new class id. 92 */ 93 public int addClass() { 94 final int id = maxId++; 95 classes.add(id); 96 return id; 97 } 98 99 /** 100 * Add an interface, and return its id. 101 * 102 * @return The new interface id. 103 */ 104 public int addInterface() { 105 final int id = maxId++; 106 interfaces.add(id); 107 return id; 108 } 109 110 /** 111 * Add an inheritance. 112 * 113 * @param sub The sub class/interface. 114 * @param sup The super class/interface 115 */ 116 public void addInherit(final int sub, 117 final int sup) { 118 HashSet<Integer> ext = extensions.get(sub); 119 120 if (ext == null) { 121 ext = new HashSet<>(); 122 extensions.put(sub, ext); 123 } 124 125 ext.add(sup); 126 } 127 128 @Override 129 public String toString() { 130 String out = ""; 131 for(int i = maxId - 1; i >= 0; i--) { 132 out += i + ": "; 133 for(int j = 0; j < maxId; j++) { 134 out += "[" + (inherits(i, j) ? "1" : "0") + "]"; 135 } 136 out += "\n"; 137 } 138 return out; 139 } 140 141 /** 142 * Indicate whether the first class inherits from the second. 143 * 144 * @param sub The possible subtype. 145 * @param sup The possible supertype. 146 * @return Whether or not {@code sub} inherits from {@code sup}. 147 */ 148 public boolean inherits(final int sub, final int sup) { 149 final Set<Integer> ext = extensions.get(sub); 150 if (ext != null) { 151 return ext.contains(sup); 152 } else { 153 return false; 154 } 155 } 156 157 /** 158 * Indicate whether a given type name is a class. 159 * 160 * @param id The type in question. 161 * @return Whether or not the type is a class. 162 */ 163 public boolean isClass(final int id) { 164 if (id == OBJECT_CLASS) return true; 165 return classes.contains(id); 166 } 167 168 /** 169 * Indicate whether a given type name is an interface. 170 * 171 * @param id The type in question. 172 * @return Whether or not the type is an interface. 173 */ 174 public boolean isInterface(final int id) { 175 if (id == OBJECT_CLASS) return false; 176 return interfaces.contains(id); 177 } 178 179 /** 180 * Get an iterator over the classes. 181 * 182 * @return An iterator over classes. 183 */ 184 public Collection<Integer> classes() { 185 return classes; 186 } 187 188 /** 189 * Get an iterator over the interfaces. 190 * 191 * @return An iterator over interfaces. 192 */ 193 public Collection<Integer> interfaces() { 194 return interfaces; 195 } 196 197 /** 198 * Get an iterator over all types. 199 * 200 * @return An iterator over all types. 201 */ 202 public Collection<Integer> types() { 203 final Set<Integer> combined = new HashSet(classes); 204 combined.addAll(interfaces); 205 return combined; 206 } 207 208 public int numClasses() { 209 return classes.size(); 210 } 211 212 public int numInterfaces() { 213 return interfaces.size(); 214 } 215 216 public int numTypes() { 217 return numClasses() + numInterfaces(); 218 } 219 220 }