Home | History | Annotate | Download | only in annotation
      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 {
     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      */
     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      */
     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      */
     86     public Annotations() {
     87         annotations = new TreeMap<CstType, Annotation>();
     88     }
     89 
     90     /** {@inheritDoc} */
     91     @Override
     92     public int hashCode() {
     93         return annotations.hashCode();
     94     }
     95 
     96     /** {@inheritDoc} */
     97     @Override
     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} */
    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} */
    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      */
    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      */
    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      */
    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      */
    210     public Collection<Annotation> getAnnotations() {
    211         return Collections.unmodifiableCollection(annotations.values());
    212     }
    213 }
    214