| /* Copyright (C) 2003 Vladimir Roubtsov. All rights reserved. |
| * |
| * This program and the accompanying materials are made available under |
| * the terms of the Common Public License v1.0 which accompanies this distribution, |
| * and is available at http://www.eclipse.org/legal/cpl-v10.html |
| * |
| * $Id: ConstantCollection.java,v 1.1.1.1 2004/05/09 16:57:45 vlad_r Exp $ |
| */ |
| package com.vladium.jcd.cls; |
| |
| import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| import com.vladium.jcd.cls.constant.*; |
| import com.vladium.jcd.lib.UDataOutputStream; |
| import com.vladium.util.ObjectIntMap; |
| |
| // ---------------------------------------------------------------------------- |
| /** |
| * @author (C) 2001, Vladimir Roubtsov |
| */ |
| final class ConstantCollection implements IConstantCollection |
| { |
| // public: ................................................................ |
| |
| // IConstantCollection: |
| |
| // ACCESSORS: |
| |
| public CONSTANT_info get (final int index) |
| { |
| final Object result = m_constants.get (index - 1); |
| |
| if (result == null) |
| throw new IllegalStateException ("assertion failure: dereferencing an invalid constant pool slot " + index); |
| |
| return (CONSTANT_info) result; |
| } |
| |
| public IConstantCollection.IConstantIterator iterator () |
| { |
| return new ConstantIterator (m_constants); |
| } |
| |
| public int find (final int type, final IConstantComparator comparator) |
| { |
| if (comparator == null) |
| throw new IllegalArgumentException ("null input: comparator"); |
| |
| for (int i = 0; i < m_constants.size (); ++ i) |
| { |
| final CONSTANT_info constant = (CONSTANT_info) m_constants.get (i); |
| |
| if ((constant != null) && (constant.tag () == type) && comparator.equals (constant)) |
| return i /* !!! */ + 1; |
| } |
| |
| return -1; |
| } |
| |
| public int findCONSTANT_Utf8 (final String value) |
| { |
| if (value == null) |
| throw new IllegalArgumentException ("null input: value"); |
| |
| // create index lazily: |
| final ObjectIntMap index = getCONSTANT_Utf8_index (); |
| final int [] result = new int [1]; |
| |
| if (index.get (value, result)) |
| return result [0] /* !!! */ + 1; |
| else |
| return -1; |
| } |
| |
| public int size () |
| { |
| return m_size; |
| } |
| |
| // Cloneable: |
| |
| /** |
| * Performs a deep copy. |
| */ |
| public Object clone () |
| { |
| try |
| { |
| final ConstantCollection _clone = (ConstantCollection) super.clone (); |
| |
| // deep copy: |
| final int constants_count = m_constants.size (); |
| _clone.m_constants = new ArrayList (constants_count); |
| for (int c = 0; c < constants_count; ++ c) |
| { |
| final CONSTANT_info constant = (CONSTANT_info) m_constants.get (c); |
| _clone.m_constants.add (constant == null ? null : constant.clone ()); |
| } |
| |
| // note: m_CONSTANT_Utf8_index is not cloned intentionally |
| |
| return _clone; |
| } |
| catch (CloneNotSupportedException e) |
| { |
| throw new InternalError (e.toString ()); |
| } |
| } |
| |
| // IClassFormatOutput: |
| |
| public void writeInClassFormat (final UDataOutputStream out) throws IOException |
| { |
| final int constant_pool_count = m_constants.size (); // note: this is not the same as size() |
| out.writeU2 (constant_pool_count + /* !!! */1); |
| |
| final ConstantIterator i = new ConstantIterator (m_constants); |
| for (CONSTANT_info entry; (entry = i.nextConstant ()) != null; ) |
| { |
| entry.writeInClassFormat (out); |
| } |
| } |
| |
| // Visitor: |
| |
| public void accept (final IClassDefVisitor visitor, final Object ctx) |
| { |
| visitor.visit (this, ctx); |
| } |
| |
| |
| // MUTATORS: |
| |
| public CONSTANT_info set (final int index, final CONSTANT_info constant) |
| { |
| final int zindex = index - 1; |
| final CONSTANT_info result = (CONSTANT_info) m_constants.get (zindex); |
| |
| if (result == null) |
| throw new IllegalStateException ("assertion failure: dereferencing an invalid constant pool slot " + index); |
| |
| if (result.width () != constant.width ()) |
| 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); |
| |
| m_constants.set (zindex, constant); |
| |
| // update the string index if it is in use: |
| if (m_CONSTANT_Utf8_index != null) |
| { |
| // remove the old index value if it exists and is equal to 'index': |
| if (result instanceof CONSTANT_Utf8_info) |
| { |
| final String mapKey = ((CONSTANT_Utf8_info) result).m_value; |
| final int [] out = new int [1]; |
| |
| if (m_CONSTANT_Utf8_index.get (mapKey, out) && (out [0] == zindex)) |
| m_CONSTANT_Utf8_index.remove (mapKey); |
| } |
| |
| // add new index value if necessary: |
| if (constant instanceof CONSTANT_Utf8_info) |
| m_CONSTANT_Utf8_index.put (((CONSTANT_Utf8_info) constant).m_value, zindex); |
| } |
| |
| return result; |
| } |
| |
| public int add (final CONSTANT_info constant) |
| { |
| m_constants.add (constant); |
| ++ m_size; |
| final int result = m_constants.size (); |
| |
| for (int width = 1; width < constant.width (); ++ width) |
| { |
| ++ m_size; |
| m_constants.add (null); // insert padding empty slots |
| } |
| |
| // update the string index if it is in use: |
| if ((m_CONSTANT_Utf8_index != null) && (constant instanceof CONSTANT_Utf8_info)) |
| m_CONSTANT_Utf8_index.put (((CONSTANT_Utf8_info) constant).m_value, result /* !!! */ - 1); |
| |
| return result; |
| } |
| |
| // protected: ............................................................. |
| |
| // package: ............................................................... |
| |
| |
| ConstantCollection (final int capacity) |
| { |
| m_constants = capacity < 0 ? new ArrayList () : new ArrayList (capacity); |
| } |
| |
| // private: ............................................................... |
| |
| |
| private static final class ConstantIterator implements IConstantCollection.IConstantIterator |
| { |
| ConstantIterator (final List/* CONSTANT_info */ constants) |
| { |
| m_constants = constants; |
| m_next_index = 1; |
| shift (); |
| } |
| |
| |
| public int nextIndex () |
| { |
| final int result = m_index; |
| shift (); |
| |
| return result; |
| } |
| |
| public CONSTANT_info nextConstant () |
| { |
| final int nextIndex = nextIndex (); |
| if (nextIndex < 0) |
| return null; |
| else |
| return (CONSTANT_info) m_constants.get (nextIndex - 1); |
| } |
| |
| public CONSTANT_info set (final CONSTANT_info constant) |
| { |
| final int zindex = m_prev_index - 1; |
| final CONSTANT_info result = (CONSTANT_info) m_constants.get (zindex); |
| |
| if (result == null) // this should never happen with iterators |
| throw new IllegalStateException ("assertion failure: dereferencing an invalid constant pool slot " + m_prev_index); |
| |
| if (result.width () != constant.width ()) |
| 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); |
| |
| m_constants.set (zindex, constant); |
| |
| return result; |
| } |
| |
| |
| private void shift () |
| { |
| m_prev_index = m_index; |
| m_index = m_next_index; |
| |
| if (m_index > 0) |
| { |
| try |
| { |
| final CONSTANT_info entry = (CONSTANT_info) m_constants.get (m_index - 1); |
| |
| m_next_index += entry.width (); |
| if (m_next_index > m_constants.size ()) m_next_index = -1; |
| } |
| catch (IndexOutOfBoundsException ioobe) // empty collection edge case |
| { |
| m_index = m_next_index = -1; |
| } |
| } |
| } |
| |
| |
| private int m_index, m_prev_index, m_next_index; |
| private List/* CONSTANT_info */ m_constants; |
| |
| } // end of nested class |
| |
| |
| private ObjectIntMap getCONSTANT_Utf8_index () |
| { |
| if (m_CONSTANT_Utf8_index == null) |
| { |
| final ObjectIntMap index = new ObjectIntMap (m_size); |
| |
| for (int i = 0; i < m_constants.size (); ++ i) |
| { |
| final CONSTANT_info constant = (CONSTANT_info) m_constants.get (i); |
| |
| if ((constant != null) && (constant.tag () == CONSTANT_Utf8_info.TAG)) |
| { |
| // it's ok to always put: the later indices will simply override the earlier ones |
| index.put (((CONSTANT_Utf8_info) constant).m_value, i); // note: unadjusted index saved here |
| } |
| } |
| |
| m_CONSTANT_Utf8_index = index; |
| } |
| |
| return m_CONSTANT_Utf8_index; |
| } |
| |
| |
| private List/* CONSTANT_info */ m_constants; // never null |
| private int m_size; |
| private transient ObjectIntMap /* String(CONSTANT_Utf value) -> int(index) */ m_CONSTANT_Utf8_index; |
| |
| } // end of class |
| // ---------------------------------------------------------------------------- |