1 /* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.dexgen.rop.annotation; 18 19 import com.android.dexgen.rop.cst.CstType; 20 import com.android.dexgen.util.MutabilityControl; 21 22 import java.util.Collection; 23 import java.util.Collections; 24 import java.util.Iterator; 25 import java.util.TreeMap; 26 27 /** 28 * List of {@link Annotation} instances. 29 */ 30 public final class Annotations extends MutabilityControl 31 implements Comparable<Annotations> { 32 /** {@code non-null;} immutable empty instance */ 33 public static final Annotations EMPTY = new Annotations(); 34 35 static { EMPTY.setImmutable()36 EMPTY.setImmutable(); 37 } 38 39 /** {@code non-null;} map from types to annotations */ 40 private final TreeMap<CstType, Annotation> annotations; 41 42 /** 43 * Constructs an immutable instance which is the combination of the 44 * two given instances. The two instances must contain disjoint sets 45 * of types. 46 * 47 * @param a1 {@code non-null;} an instance 48 * @param a2 {@code non-null;} the other instance 49 * @return {@code non-null;} the combination 50 * @throws IllegalArgumentException thrown if there is a duplicate type 51 */ combine(Annotations a1, Annotations a2)52 public static Annotations combine(Annotations a1, Annotations a2) { 53 Annotations result = new Annotations(); 54 55 result.addAll(a1); 56 result.addAll(a2); 57 result.setImmutable(); 58 59 return result; 60 } 61 62 /** 63 * Constructs an immutable instance which is the combination of the 64 * given instance with the given additional annotation. The latter's 65 * type must not already appear in the former. 66 * 67 * @param annotations {@code non-null;} the instance to augment 68 * @param annotation {@code non-null;} the additional annotation 69 * @return {@code non-null;} the combination 70 * @throws IllegalArgumentException thrown if there is a duplicate type 71 */ combine(Annotations annotations, Annotation annotation)72 public static Annotations combine(Annotations annotations, 73 Annotation annotation) { 74 Annotations result = new Annotations(); 75 76 result.addAll(annotations); 77 result.add(annotation); 78 result.setImmutable(); 79 80 return result; 81 } 82 83 /** 84 * Constructs an empty instance. 85 */ Annotations()86 public Annotations() { 87 annotations = new TreeMap<CstType, Annotation>(); 88 } 89 90 /** {@inheritDoc} */ 91 @Override hashCode()92 public int hashCode() { 93 return annotations.hashCode(); 94 } 95 96 /** {@inheritDoc} */ 97 @Override equals(Object other)98 public boolean equals(Object other) { 99 if (! (other instanceof Annotations)) { 100 return false; 101 } 102 103 Annotations otherAnnotations = (Annotations) other; 104 105 return annotations.equals(otherAnnotations.annotations); 106 } 107 108 /** {@inheritDoc} */ compareTo(Annotations other)109 public int compareTo(Annotations other) { 110 Iterator<Annotation> thisIter = annotations.values().iterator(); 111 Iterator<Annotation> otherIter = other.annotations.values().iterator(); 112 113 while (thisIter.hasNext() && otherIter.hasNext()) { 114 Annotation thisOne = thisIter.next(); 115 Annotation otherOne = otherIter.next(); 116 117 int result = thisOne.compareTo(otherOne); 118 if (result != 0) { 119 return result; 120 } 121 } 122 123 if (thisIter.hasNext()) { 124 return 1; 125 } else if (otherIter.hasNext()) { 126 return -1; 127 } 128 129 return 0; 130 } 131 132 /** {@inheritDoc} */ toString()133 public String toString() { 134 StringBuilder sb = new StringBuilder(); 135 boolean first = true; 136 137 sb.append("annotations{"); 138 139 for (Annotation a : annotations.values()) { 140 if (first) { 141 first = false; 142 } else { 143 sb.append(", "); 144 } 145 sb.append(a.toHuman()); 146 } 147 148 sb.append("}"); 149 return sb.toString(); 150 } 151 152 /** 153 * Gets the number of elements in this instance. 154 * 155 * @return {@code >= 0;} the size 156 */ size()157 public int size() { 158 return annotations.size(); 159 } 160 161 /** 162 * Adds an element to this instance. There must not already be an 163 * element of the same type. 164 * 165 * @param annotation {@code non-null;} the element to add 166 * @throws IllegalArgumentException thrown if there is a duplicate type 167 */ add(Annotation annotation)168 public void add(Annotation annotation) { 169 throwIfImmutable(); 170 171 if (annotation == null) { 172 throw new NullPointerException("annotation == null"); 173 } 174 175 CstType type = annotation.getType(); 176 177 if (annotations.containsKey(type)) { 178 throw new IllegalArgumentException("duplicate type: " + 179 type.toHuman()); 180 } 181 182 annotations.put(type, annotation); 183 } 184 185 /** 186 * Adds all of the elements of the given instance to this one. The 187 * instances must not have any duplicate types. 188 * 189 * @param toAdd {@code non-null;} the annotations to add 190 * @throws IllegalArgumentException thrown if there is a duplicate type 191 */ addAll(Annotations toAdd)192 public void addAll(Annotations toAdd) { 193 throwIfImmutable(); 194 195 if (toAdd == null) { 196 throw new NullPointerException("toAdd == null"); 197 } 198 199 for (Annotation a : toAdd.annotations.values()) { 200 add(a); 201 } 202 } 203 204 /** 205 * Gets the set of annotations contained in this instance. The 206 * result is always unmodifiable. 207 * 208 * @return {@code non-null;} the set of annotations 209 */ getAnnotations()210 public Collection<Annotation> getAnnotations() { 211 return Collections.unmodifiableCollection(annotations.values()); 212 } 213 } 214