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