/* 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: AttributeCollection.java,v 1.1.1.1 2004/05/09 16:57:44 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.attribute.*; import com.vladium.jcd.lib.UDataOutputStream; import com.vladium.util.asserts.$assert; // ---------------------------------------------------------------------------- /** * @author (C) 2001, Vlad Roubtsov */ final class AttributeCollection implements IAttributeCollection { // public: ................................................................ // TODO: extend ItemCollection into all XXXCollection classes ? // ACCESSORS: public final Attribute_info get (final int offset) { return (Attribute_info) m_attributes.get (offset); } public final boolean hasSynthetic () { return m_syntheticRefCount > 0; } public final boolean hasBridge () { return m_bridgeRefCount > 0; } public final InnerClassesAttribute_info getInnerClassesAttribute () { final int innerClassesAttributeOffset = m_innerClassesAttributeOffset; if (innerClassesAttributeOffset < 0) return null; else return (InnerClassesAttribute_info) get (innerClassesAttributeOffset); } public final int size () { return m_attributes.size (); } public final long length () { // TODO: cache? long result = 2; int _attributes_count = m_attributes.size (); // use size() if this class becomes non-final for (int i = 0; i < _attributes_count; i++) result += get (i).length (); return result; } // Cloneable: /** * Performs a deep copy. */ public Object clone () { try { final AttributeCollection _clone = (AttributeCollection) super.clone (); // deep clone: final int attributes_count = m_attributes.size (); // use size() if this class becomes non-final _clone.m_attributes = new ArrayList (attributes_count); for (int a = 0; a < attributes_count; ++ a) { _clone.m_attributes.add (((Attribute_info) m_attributes.get (a)).clone ()); } return _clone; } catch (CloneNotSupportedException e) { throw new InternalError (e.toString ()); } } // IClassFormatOutput: public void writeInClassFormat (final UDataOutputStream out) throws IOException { int attributes_count = size (); out.writeU2 (attributes_count); for (int i = 0; i < attributes_count; i++) { get (i).writeInClassFormat (out); } } // Visitor: public void accept (final IClassDefVisitor visitor, final Object ctx) { visitor.visit (this, ctx); } // MUTATORS: public int add (final Attribute_info attribute) { final List/* Attribute_info */ attributes = m_attributes; final int result = attributes.size (); attributes.add (attribute); if (attribute instanceof SyntheticAttribute_info) ++ m_syntheticRefCount; else if (attribute instanceof InnerClassesAttribute_info) { if (m_innerClassesAttributeOffset >= 0) throw new IllegalArgumentException ("this attribute collection already has an InnerClasses attribute"); m_innerClassesAttributeOffset = result; } else if (attribute instanceof BridgeAttribute_info) ++ m_bridgeRefCount; if (DISALLOW_MULTIPLE_SYNTHETIC_ATTRIBUTES && $assert.ENABLED) $assert.ASSERT (m_syntheticRefCount >= 0 && m_syntheticRefCount <= 1, "bad synthetic attribute count: " + m_syntheticRefCount); return result; } public Attribute_info set (final int offset, final Attribute_info attribute) { final Attribute_info result = (Attribute_info) m_attributes.set (offset, attribute); if (result instanceof SyntheticAttribute_info) -- m_syntheticRefCount; else if (result instanceof InnerClassesAttribute_info) m_innerClassesAttributeOffset = -1; else if (result instanceof BridgeAttribute_info) -- m_bridgeRefCount; if (attribute instanceof SyntheticAttribute_info) ++ m_syntheticRefCount; else if (attribute instanceof InnerClassesAttribute_info) m_innerClassesAttributeOffset = offset; else if (attribute instanceof BridgeAttribute_info) ++ m_bridgeRefCount; if (DISALLOW_MULTIPLE_SYNTHETIC_ATTRIBUTES && $assert.ENABLED) $assert.ASSERT (m_syntheticRefCount >= 0 && m_syntheticRefCount <= 1, "bad synthetic attribute count: " + m_syntheticRefCount); return result; } public Attribute_info remove (final int offset) { final Attribute_info result = (Attribute_info) m_attributes.remove (offset); if (result instanceof SyntheticAttribute_info) -- m_syntheticRefCount; else if (result instanceof InnerClassesAttribute_info) m_innerClassesAttributeOffset = -1; else if (result instanceof BridgeAttribute_info) -- m_bridgeRefCount; if (DISALLOW_MULTIPLE_SYNTHETIC_ATTRIBUTES && $assert.ENABLED) $assert.ASSERT (m_syntheticRefCount >= 0 && m_syntheticRefCount <= 1, "bad synthetic attribute count: " + m_syntheticRefCount); return result; } // protected: ............................................................. // package: ............................................................... AttributeCollection (final int capacity) { m_attributes = capacity < 0 ? new ArrayList () : new ArrayList (capacity); m_innerClassesAttributeOffset = -1; } // private: ............................................................... private List/* Attribute_info */ m_attributes; // never null private transient int m_syntheticRefCount, m_bridgeRefCount; private transient int m_innerClassesAttributeOffset; // note: the spec does not disallow multiple synthetic attributes private static final boolean DISALLOW_MULTIPLE_SYNTHETIC_ATTRIBUTES = false; // note: the spec disallows multiple inner classes attributes } // end of class // ----------------------------------------------------------------------------