1579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson/*
2579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Copyright (C) 2007 The Android Open Source Project
3579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *
4579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Licensed under the Apache License, Version 2.0 (the "License");
5579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * you may not use this file except in compliance with the License.
6579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * You may obtain a copy of the License at
7579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *
8579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *      http://www.apache.org/licenses/LICENSE-2.0
9579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *
10579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Unless required by applicable law or agreed to in writing, software
11579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * distributed under the License is distributed on an "AS IS" BASIS,
12579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * See the License for the specific language governing permissions and
14579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * limitations under the License.
15579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson */
16579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
17579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonpackage com.android.dx.rop.annotation;
18579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
19579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.cst.CstType;
20579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.util.MutabilityControl;
21579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
22579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.util.Collection;
23579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.util.Collections;
24579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.util.Iterator;
25579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.util.TreeMap;
26579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
27579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson/**
28579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * List of {@link Annotation} instances.
29579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson */
30579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonpublic final class Annotations extends MutabilityControl
31579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        implements Comparable<Annotations> {
32579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@code non-null;} immutable empty instance */
33579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static final Annotations EMPTY = new Annotations();
34579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
35579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    static {
36579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        EMPTY.setImmutable();
37579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
38579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
39579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@code non-null;} map from types to annotations */
40579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private final TreeMap<CstType, Annotation> annotations;
41579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
42579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
43579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Constructs an immutable instance which is the combination of the
44579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * two given instances. The two instances must contain disjoint sets
45579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * of types.
46579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
47579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param a1 {@code non-null;} an instance
48579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param a2 {@code non-null;} the other instance
49579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} the combination
50579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @throws IllegalArgumentException thrown if there is a duplicate type
51579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
52579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static Annotations combine(Annotations a1, Annotations a2) {
53579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Annotations result = new Annotations();
54579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
55579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        result.addAll(a1);
56579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        result.addAll(a2);
57579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        result.setImmutable();
58579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
59579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return result;
60579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
61579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
62579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
63579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Constructs an immutable instance which is the combination of the
64579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * given instance with the given additional annotation. The latter's
65579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * type must not already appear in the former.
66579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
67579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param annotations {@code non-null;} the instance to augment
68579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param annotation {@code non-null;} the additional annotation
69579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} the combination
70579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @throws IllegalArgumentException thrown if there is a duplicate type
71579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
72579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static Annotations combine(Annotations annotations,
73579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            Annotation annotation) {
74579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Annotations result = new Annotations();
75579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
76579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        result.addAll(annotations);
77579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        result.add(annotation);
78579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        result.setImmutable();
79579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
80579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return result;
81579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
82579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
83579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
84579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Constructs an empty instance.
85579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
86579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public Annotations() {
87579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        annotations = new TreeMap<CstType, Annotation>();
88579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
89579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
90579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@inheritDoc} */
91579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    @Override
92579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public int hashCode() {
93579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return annotations.hashCode();
94579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
95579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
96579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@inheritDoc} */
97579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    @Override
98579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public boolean equals(Object other) {
99579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (! (other instanceof Annotations)) {
100579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return false;
101579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
102579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
103579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Annotations otherAnnotations = (Annotations) other;
104579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
105579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return annotations.equals(otherAnnotations.annotations);
106579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
107579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
108579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@inheritDoc} */
109579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public int compareTo(Annotations other) {
110579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Iterator<Annotation> thisIter = annotations.values().iterator();
111579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Iterator<Annotation> otherIter = other.annotations.values().iterator();
112579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
113579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        while (thisIter.hasNext() && otherIter.hasNext()) {
114579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            Annotation thisOne = thisIter.next();
115579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            Annotation otherOne = otherIter.next();
116579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
117579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            int result = thisOne.compareTo(otherOne);
118579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (result != 0) {
119579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                return result;
120579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
121579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
122579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
123579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (thisIter.hasNext()) {
124579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return 1;
125579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } else if (otherIter.hasNext()) {
126579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return -1;
127579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
128579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
129579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return 0;
130579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
131579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
132579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@inheritDoc} */
133579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public String toString() {
134579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        StringBuilder sb = new StringBuilder();
135579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        boolean first = true;
136579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
137579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        sb.append("annotations{");
138579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
139579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        for (Annotation a : annotations.values()) {
140579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (first) {
141579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                first = false;
142579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            } else {
143579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                sb.append(", ");
144579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
145579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            sb.append(a.toHuman());
146579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
147579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
148579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        sb.append("}");
149579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return sb.toString();
150579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
151579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
152579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
153579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Gets the number of elements in this instance.
154579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
155579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code >= 0;} the size
156579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
157579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public int size() {
158579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return annotations.size();
159579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
160579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
161579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
162579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Adds an element to this instance. There must not already be an
163579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * element of the same type.
164579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
165579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param annotation {@code non-null;} the element to add
166579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @throws IllegalArgumentException thrown if there is a duplicate type
167579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
168579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void add(Annotation annotation) {
169579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        throwIfImmutable();
170579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
171579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (annotation == null) {
172579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new NullPointerException("annotation == null");
173579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
174579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
175579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        CstType type = annotation.getType();
176579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
177579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (annotations.containsKey(type)) {
178579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new IllegalArgumentException("duplicate type: " +
179579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    type.toHuman());
180579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
181579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
182579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        annotations.put(type, annotation);
183579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
184579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
185579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
186579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Adds all of the elements of the given instance to this one. The
187579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * instances must not have any duplicate types.
188579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
189579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param toAdd {@code non-null;} the annotations to add
190579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @throws IllegalArgumentException thrown if there is a duplicate type
191579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
192579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void addAll(Annotations toAdd) {
193579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        throwIfImmutable();
194579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
195579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (toAdd == null) {
196579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new NullPointerException("toAdd == null");
197579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
198579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
199579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        for (Annotation a : toAdd.annotations.values()) {
200579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            add(a);
201579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
202579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
203579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
204579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
205579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Gets the set of annotations contained in this instance. The
206579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * result is always unmodifiable.
207579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
208579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} the set of annotations
209579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
210579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public Collection<Annotation> getAnnotations() {
211579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return Collections.unmodifiableCollection(annotations.values());
212579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
213579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson}
214