Home | History | Annotate | Download | only in util
      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.dx.util;
     18 
     19 import java.util.Arrays;
     20 
     21 /**
     22  * A list of labeled items, allowing easy lookup by label.
     23  */
     24 public class LabeledList extends FixedSizeList {
     25     /**
     26      * Sparse array indexed by label to FixedSizeList index;
     27      * {@code -1} for an invalid label.
     28      */
     29     private final IntList labelToIndex;
     30 
     31     /** @inheritDoc */
     32     public LabeledList(int size) {
     33         super(size);
     34 
     35         labelToIndex = new IntList(size);
     36     }
     37 
     38     /**
     39      * Constructs a new instance that is a copy of the old instance.
     40      *
     41      * @param old instance to copy
     42      */
     43     public LabeledList(LabeledList old) {
     44         super(old.size());
     45         labelToIndex = old.labelToIndex.mutableCopy();
     46 
     47         int sz = old.size();
     48 
     49         for (int i = 0; i < sz; i++) {
     50             Object one = old.get0(i);
     51             if (one != null) {
     52                 set0(i, one);
     53             }
     54         }
     55     }
     56 
     57     /**
     58      * Gets the maximum label (exclusive) of any block added to this instance.
     59      *
     60      * @return {@code >= 0;} the maximum label
     61      */
     62     public final int getMaxLabel() {
     63         int sz = labelToIndex.size();
     64 
     65         // Gobble any deleted labels that may be at the end.
     66         int i;
     67         for (i = sz - 1; (i >= 0) && (labelToIndex.get(i) < 0); i--)
     68             /*empty*/ ;
     69 
     70         int newSize = i + 1;
     71 
     72         labelToIndex.shrink(newSize);
     73 
     74         return newSize;
     75     }
     76 
     77     /**
     78      * Removes a label from the label-to-index mapping.
     79      *
     80      * @param oldLabel label to remove
     81      */
     82     private void removeLabel(int oldLabel) {
     83         labelToIndex.set(oldLabel, -1);
     84     }
     85 
     86     /**
     87      * Adds a label and index to the label-to-index mapping.
     88      *
     89      * @param label new label
     90      * @param index index of block.
     91      */
     92     private void addLabelIndex(int label, int index) {
     93         int origSz = labelToIndex.size();
     94 
     95         for (int i = 0; i <= (label - origSz); i++) {
     96             labelToIndex.add(-1);
     97         }
     98 
     99         labelToIndex.set(label, index);
    100     }
    101 
    102     /**
    103      * Gets the index of the first item in the list with the given
    104      * label, if any.
    105      *
    106      * @param label {@code >= 0;} the label to look for
    107      * @return {@code >= -1;} the index of the so-labelled item, or {@code -1}
    108      * if none is found
    109      */
    110     public final int indexOfLabel(int label) {
    111         if (label >= labelToIndex.size()) {
    112             return -1;
    113         } else {
    114             return labelToIndex.get(label);
    115         }
    116     }
    117 
    118     /**
    119      * Gets an array containing all of the labels used in this instance,
    120      * in order. The returned array is freshly-allocated and so may be
    121      * modified safely by the caller without impacting this instance.
    122      *
    123      * @return {@code non-null;} ordered array of labels
    124      * @throws NullPointerException thrown if there are any {@code null}
    125      * items in this instance
    126      */
    127     public final int[] getLabelsInOrder() {
    128         int sz = size();
    129         int[] result = new int[sz];
    130 
    131         for (int i = 0; i < sz; i++) {
    132             LabeledItem li = (LabeledItem) get0(i);
    133             if (li == null) {
    134                 throw new NullPointerException("null at index " + i);
    135             }
    136             result[i] = li.getLabel();
    137         }
    138 
    139         Arrays.sort(result);
    140         return result;
    141     }
    142 
    143     /** @inheritDoc */
    144     @Override
    145     public void shrinkToFit() {
    146         super.shrinkToFit();
    147 
    148         rebuildLabelToIndex();
    149     }
    150 
    151     /**
    152      * Rebuilds the label-to-index mapping after a {@code shrinkToFit()}.
    153      * Note: This assumes that the labels that are in the list are the
    154      * same, although the indicies may have changed.
    155      */
    156     private void rebuildLabelToIndex() {
    157         int szItems = size();
    158 
    159         for (int i = 0; i < szItems; i++) {
    160             LabeledItem li = (LabeledItem) get0(i);
    161 
    162             if (li != null) {
    163                 labelToIndex.set(li.getLabel(), i);
    164             }
    165         }
    166     }
    167 
    168     /**
    169      * Sets the element at the given index.
    170      *
    171      * @param n {@code >= 0, < size();} which element
    172      * @param item {@code null-ok;} the value to store
    173      */
    174     protected void set(int n, LabeledItem item) {
    175         LabeledItem old = (LabeledItem) getOrNull0(n);
    176 
    177         set0(n, item);
    178 
    179         if (old != null) {
    180             removeLabel(old.getLabel());
    181         }
    182 
    183         if (item != null) {
    184             addLabelIndex(item.getLabel(), n);
    185         }
    186     }
    187 }
    188