blob: 5831a12a3f4ea408e4549643a53b55cc308c4e2c [file] [log] [blame]
/* 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
// ----------------------------------------------------------------------------