1/*
2 * Copyright (c) 2016, 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
24package selectionresolution;
25
26import java.util.Arrays;
27import java.util.Collection;
28import java.util.HashMap;
29import java.util.HashSet;
30import java.util.Set;
31import java.util.Map;
32
33/**
34 * A representation of a class/interface hierarchy graph (just the
35 * graph; the class data is represented elsewhere).
36 */
37public class HierarchyShape {
38    public static final int OBJECT_CLASS = -1;
39
40    protected int maxId;
41
42    /**
43     * The names of all the classes.
44     */
45    private final HashSet<Integer> classes;
46
47    /**
48     * The names of all the interfaces.
49     */
50    private final HashSet<Integer> interfaces;
51    private final HashMap<Integer, HashSet<Integer>> extensions;
52
53    /**
54     * Create an empty hierarchy shape.
55     */
56    public HierarchyShape() {
57        this(0, new HashSet<>(), new HashSet<>(), new HashMap<>());
58    }
59
60    private HierarchyShape(final int maxId,
61                          final HashSet<Integer> classes,
62                          final HashSet<Integer> interfaces,
63                          final HashMap<Integer, HashSet<Integer>> extensions) {
64        this.maxId = maxId;
65        this.classes = classes;
66        this.interfaces = interfaces;
67        this.extensions = extensions;
68    }
69
70    /**
71     * Make a copy of this hierarchy shape.
72     */
73    public HierarchyShape copy() {
74        final HashMap<Integer, HashSet<Integer>> newextensions = new HashMap<>();
75
76        for(final Map.Entry<Integer, HashSet<Integer>> entry :
77                extensions.entrySet()) {
78            newextensions.put(entry.getKey(),
79                              (HashSet<Integer>)entry.getValue().clone());
80        }
81
82        return new HierarchyShape(maxId, (HashSet<Integer>) classes.clone(),
83                                  (HashSet<Integer>) interfaces.clone(),
84                                  newextensions);
85    }
86
87    /**
88     * Add a class, and return its id.
89     *
90     * @return The new class id.
91     */
92    public int addClass() {
93        final int id = maxId++;
94        classes.add(id);
95        return id;
96    }
97
98    /**
99     * Add an interface, and return its id.
100     *
101     * @return The new interface id.
102     */
103    public int addInterface() {
104        final int id = maxId++;
105        interfaces.add(id);
106        return id;
107    }
108
109    /**
110     * Add an inheritance.
111     *
112     * @param sub The sub class/interface.
113     * @param sup The super class/interface
114     */
115    public void addInherit(final int sub,
116                           final int sup) {
117        HashSet<Integer> ext = extensions.get(sub);
118
119        if (ext == null) {
120            ext = new HashSet<>();
121            extensions.put(sub, ext);
122        }
123
124        ext.add(sup);
125    }
126
127    @Override
128    public String toString() {
129        String out = "";
130        for(int i = maxId - 1; i >= 0; i--) {
131            out += i + ": ";
132            for(int j = 0; j < maxId; j++) {
133                out += "[" + (inherits(i, j) ? "1" : "0") + "]";
134            }
135            out += "\n";
136        }
137        return out;
138    }
139
140    /**
141     * Indicate whether the first class inherits from the second.
142     *
143     * @param sub The possible subtype.
144     * @param sup The possible supertype.
145     * @return Whether or not {@code sub} inherits from {@code sup}.
146     */
147    public boolean inherits(final int sub, final int sup) {
148        final Set<Integer> ext = extensions.get(sub);
149        if (ext != null) {
150            return ext.contains(sup);
151        } else {
152            return false;
153        }
154    }
155
156    /**
157     * Indicate whether a given type name is a class.
158     *
159     * @param id The type in question.
160     * @return Whether or not the type is a class.
161     */
162    public boolean isClass(final int id) {
163        if (id == OBJECT_CLASS) {
164            return true;
165        }
166        return classes.contains(id);
167    }
168
169    /**
170     * Indicate whether a given type name is an interface.
171     *
172     * @param id The type in question.
173     * @return Whether or not the type is an interface.
174     */
175    public boolean isInterface(final int id) {
176        if (id == OBJECT_CLASS) {
177            return false;
178        }
179        return interfaces.contains(id);
180    }
181
182    /**
183     * Get an iterator over the classes.
184     *
185     * @return An iterator over classes.
186     */
187    public Collection<Integer> classes() {
188        return classes;
189    }
190
191    /**
192     * Get an iterator over the interfaces.
193     *
194     * @return An iterator over interfaces.
195     */
196    public Collection<Integer> interfaces() {
197        return interfaces;
198    }
199
200    /**
201     * Get an iterator over all types.
202     *
203     * @return An iterator over all types.
204     */
205    public Collection<Integer> types() {
206        final Set<Integer> combined = new HashSet(classes);
207        combined.addAll(interfaces);
208        return combined;
209    }
210
211    public int numClasses() {
212        return classes.size();
213    }
214
215    public int numInterfaces() {
216        return interfaces.size();
217    }
218
219    public int numTypes() {
220        return numClasses() + numInterfaces();
221    }
222
223}
224