Home | History | Annotate | Download | only in cls
      1 /* Copyright (C) 2003 Vladimir Roubtsov. All rights reserved.
      2  *
      3  * This program and the accompanying materials are made available under
      4  * the terms of the Common Public License v1.0 which accompanies this distribution,
      5  * and is available at http://www.eclipse.org/legal/cpl-v10.html
      6  *
      7  * $Id: ConstantCollection.java,v 1.1.1.1 2004/05/09 16:57:45 vlad_r Exp $
      8  */
      9 package com.vladium.jcd.cls;
     10 
     11 import java.io.IOException;
     12 import java.util.ArrayList;
     13 import java.util.List;
     14 
     15 import com.vladium.jcd.cls.constant.*;
     16 import com.vladium.jcd.lib.UDataOutputStream;
     17 import com.vladium.util.ObjectIntMap;
     18 
     19 // ----------------------------------------------------------------------------
     20 /**
     21  * @author (C) 2001, Vladimir Roubtsov
     22  */
     23 final class ConstantCollection implements IConstantCollection
     24 {
     25     // public: ................................................................
     26 
     27     // IConstantCollection:
     28 
     29     // ACCESSORS:
     30 
     31     public CONSTANT_info get (final int index)
     32     {
     33         final Object result = m_constants.get (index - 1);
     34 
     35         if (result == null)
     36             throw new IllegalStateException ("assertion failure: dereferencing an invalid constant pool slot " + index);
     37 
     38         return (CONSTANT_info) result;
     39     }
     40 
     41     public IConstantCollection.IConstantIterator iterator ()
     42     {
     43         return new ConstantIterator (m_constants);
     44     }
     45 
     46     public int find (final int type, final IConstantComparator comparator)
     47     {
     48         if (comparator == null)
     49             throw new IllegalArgumentException ("null input: comparator");
     50 
     51         for (int i = 0; i < m_constants.size (); ++ i)
     52         {
     53             final CONSTANT_info constant = (CONSTANT_info) m_constants.get (i);
     54 
     55             if ((constant != null) && (constant.tag () == type) && comparator.equals (constant))
     56                 return i /* !!! */ + 1;
     57         }
     58 
     59         return -1;
     60     }
     61 
     62     public int findCONSTANT_Utf8 (final String value)
     63     {
     64         if (value == null)
     65             throw new IllegalArgumentException ("null input: value");
     66 
     67         // create index lazily:
     68         final ObjectIntMap index = getCONSTANT_Utf8_index ();
     69         final int [] result = new int [1];
     70 
     71         if (index.get (value, result))
     72             return result [0] /* !!! */ + 1;
     73         else
     74             return -1;
     75     }
     76 
     77     public int size ()
     78     {
     79         return m_size;
     80     }
     81 
     82     // Cloneable:
     83 
     84     /**
     85      * Performs a deep copy.
     86      */
     87     public Object clone ()
     88     {
     89         try
     90         {
     91             final ConstantCollection _clone = (ConstantCollection) super.clone ();
     92 
     93             // deep copy:
     94             final int constants_count = m_constants.size ();
     95             _clone.m_constants = new ArrayList (constants_count);
     96             for (int c = 0; c < constants_count; ++ c)
     97             {
     98                 final CONSTANT_info constant = (CONSTANT_info) m_constants.get (c);
     99                 _clone.m_constants.add (constant == null ? null : constant.clone ());
    100             }
    101 
    102             // note: m_CONSTANT_Utf8_index is not cloned intentionally
    103 
    104             return _clone;
    105         }
    106         catch (CloneNotSupportedException e)
    107         {
    108             throw new InternalError (e.toString ());
    109         }
    110     }
    111 
    112     // IClassFormatOutput:
    113 
    114     public void writeInClassFormat (final UDataOutputStream out) throws IOException
    115     {
    116         final int constant_pool_count = m_constants.size (); // note: this is not the same as size()
    117         out.writeU2 (constant_pool_count + /* !!! */1);
    118 
    119         final ConstantIterator i = new ConstantIterator (m_constants);
    120         for (CONSTANT_info entry; (entry = i.nextConstant ()) != null; )
    121         {
    122             entry.writeInClassFormat (out);
    123         }
    124     }
    125 
    126     // Visitor:
    127 
    128     public void accept (final IClassDefVisitor visitor, final Object ctx)
    129     {
    130         visitor.visit (this, ctx);
    131     }
    132 
    133 
    134     // MUTATORS:
    135 
    136     public CONSTANT_info set (final int index, final CONSTANT_info constant)
    137     {
    138         final int zindex = index - 1;
    139         final CONSTANT_info result = (CONSTANT_info) m_constants.get (zindex);
    140 
    141         if (result == null)
    142             throw new IllegalStateException ("assertion failure: dereferencing an invalid constant pool slot " + index);
    143 
    144         if (result.width () != constant.width ())
    145             throw new IllegalArgumentException ("assertion failure: can't set entry of type [" + result.getClass ().getName () + "] to an entry of type [" + result.getClass ().getName () + "] at pool slot " + index);
    146 
    147         m_constants.set (zindex, constant);
    148 
    149         // update the string index if it is in use:
    150         if (m_CONSTANT_Utf8_index != null)
    151         {
    152             // remove the old index value if it exists and is equal to 'index':
    153             if (result instanceof CONSTANT_Utf8_info)
    154             {
    155                 final String mapKey = ((CONSTANT_Utf8_info) result).m_value;
    156                 final int [] out = new int [1];
    157 
    158                 if (m_CONSTANT_Utf8_index.get (mapKey, out) && (out [0] == zindex))
    159                     m_CONSTANT_Utf8_index.remove (mapKey);
    160             }
    161 
    162             // add new index value if necessary:
    163             if (constant instanceof CONSTANT_Utf8_info)
    164                 m_CONSTANT_Utf8_index.put (((CONSTANT_Utf8_info) constant).m_value, zindex);
    165         }
    166 
    167         return result;
    168     }
    169 
    170     public int add (final CONSTANT_info constant)
    171     {
    172         m_constants.add (constant);
    173         ++ m_size;
    174         final int result = m_constants.size ();
    175 
    176         for (int width = 1; width < constant.width (); ++ width)
    177         {
    178             ++ m_size;
    179             m_constants.add (null); // insert padding empty slots
    180         }
    181 
    182         // update the string index if it is in use:
    183         if ((m_CONSTANT_Utf8_index != null) && (constant instanceof CONSTANT_Utf8_info))
    184             m_CONSTANT_Utf8_index.put (((CONSTANT_Utf8_info) constant).m_value, result /* !!! */ - 1);
    185 
    186         return result;
    187     }
    188 
    189     // protected: .............................................................
    190 
    191     // package: ...............................................................
    192 
    193 
    194     ConstantCollection (final int capacity)
    195     {
    196         m_constants = capacity < 0 ? new ArrayList () : new ArrayList (capacity);
    197     }
    198 
    199     // private: ...............................................................
    200 
    201 
    202     private static final class ConstantIterator implements IConstantCollection.IConstantIterator
    203     {
    204         ConstantIterator (final List/* CONSTANT_info */ constants)
    205         {
    206             m_constants = constants;
    207             m_next_index = 1;
    208             shift ();
    209         }
    210 
    211 
    212         public int nextIndex ()
    213         {
    214             final int result = m_index;
    215             shift ();
    216 
    217             return result;
    218         }
    219 
    220         public CONSTANT_info nextConstant ()
    221         {
    222             final int nextIndex = nextIndex ();
    223             if (nextIndex < 0)
    224                 return null;
    225             else
    226                 return (CONSTANT_info) m_constants.get (nextIndex - 1);
    227         }
    228 
    229         public CONSTANT_info set (final CONSTANT_info constant)
    230         {
    231             final int zindex = m_prev_index - 1;
    232             final CONSTANT_info result = (CONSTANT_info) m_constants.get (zindex);
    233 
    234             if (result == null) // this should never happen with iterators
    235                 throw new IllegalStateException ("assertion failure: dereferencing an invalid constant pool slot " + m_prev_index);
    236 
    237             if (result.width () != constant.width ())
    238                 throw new IllegalArgumentException ("assertion failure: can't set entry of type [" + result.getClass ().getName () + "] to an entry of type [" + result.getClass ().getName () + "] at pool slot " + m_prev_index);
    239 
    240             m_constants.set (zindex, constant);
    241 
    242             return result;
    243         }
    244 
    245 
    246         private void shift ()
    247         {
    248             m_prev_index = m_index;
    249             m_index = m_next_index;
    250 
    251             if (m_index > 0)
    252             {
    253                 try
    254                 {
    255                     final CONSTANT_info entry = (CONSTANT_info) m_constants.get (m_index - 1);
    256 
    257                     m_next_index += entry.width ();
    258                     if (m_next_index > m_constants.size ()) m_next_index = -1;
    259                 }
    260                 catch (IndexOutOfBoundsException ioobe) // empty collection edge case
    261                 {
    262                     m_index = m_next_index = -1;
    263                 }
    264             }
    265         }
    266 
    267 
    268         private int m_index, m_prev_index, m_next_index;
    269         private List/* CONSTANT_info */ m_constants;
    270 
    271     } // end of nested class
    272 
    273 
    274     private ObjectIntMap getCONSTANT_Utf8_index ()
    275     {
    276         if (m_CONSTANT_Utf8_index == null)
    277         {
    278             final ObjectIntMap index = new ObjectIntMap (m_size);
    279 
    280             for (int i = 0; i < m_constants.size (); ++ i)
    281             {
    282                 final CONSTANT_info constant = (CONSTANT_info) m_constants.get (i);
    283 
    284                 if ((constant != null) && (constant.tag () == CONSTANT_Utf8_info.TAG))
    285                 {
    286                     // it's ok to always put: the later indices will simply override the earlier ones
    287                     index.put (((CONSTANT_Utf8_info) constant).m_value, i); // note: unadjusted index saved here
    288                 }
    289             }
    290 
    291             m_CONSTANT_Utf8_index = index;
    292         }
    293 
    294         return m_CONSTANT_Utf8_index;
    295     }
    296 
    297 
    298     private List/* CONSTANT_info */ m_constants; // never null
    299     private int m_size;
    300     private transient ObjectIntMap /* String(CONSTANT_Utf value) -> int(index) */ m_CONSTANT_Utf8_index;
    301 
    302 } // end of class
    303 // ----------------------------------------------------------------------------
    304