/******************************************************************************* * Copyright (c) 2004, 2009 QNX Software Systems and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * QNX Software Systems - Initial API and implementation *******************************************************************************/ package org.eclipse.cdt.debug.internal.core.model; import java.math.BigInteger; import java.util.HashMap; import java.util.Map; import org.eclipse.cdt.core.IAddress; import org.eclipse.cdt.core.IAddressFactory; import org.eclipse.cdt.debug.core.cdi.CDIException; import org.eclipse.cdt.debug.core.cdi.model.ICDIVariable; import org.eclipse.cdt.debug.core.cdi.model.type.ICDIArrayValue; import org.eclipse.cdt.debug.core.cdi.model.type.ICDIPointerValue; import org.eclipse.cdt.debug.core.cdi.model.type.ICDIType; import org.eclipse.cdt.debug.core.model.CVariableFormat; import org.eclipse.cdt.debug.core.model.ICType; import org.eclipse.debug.core.DebugException; import org.eclipse.debug.core.model.IIndexedValue; import org.eclipse.debug.core.model.IVariable; /** * A value containing an array of variables. */ public class CIndexedValue extends AbstractCValue implements IIndexedValue { /** * The underlying CDI value. */ private ICDIArrayValue fCDIValue; /** * Child variables. Only the variables from loaded partitions will be held. * Use map instead of a java array to scale for large number of children. */ private Map<Integer, IVariable> fVariables; /** * The index of the first variable contained in this value. */ private int fOffset; /** * The number of entries in this indexed collection. */ private int fSize; /** * The type of this value. */ private ICType fType; /** * Constructor for CIndexedValue. */ public CIndexedValue( AbstractCVariable parent, ICDIArrayValue cdiValue, int offset, int size ) { super( parent ); fVariables = new HashMap<Integer, IVariable>(getPreferredPartitionSize()); fCDIValue = cdiValue; fOffset = offset; fSize = size; } /* (non-Javadoc) * @see org.eclipse.cdt.debug.internal.core.model.AbstractCValue#setChanged(boolean) */ protected void setChanged( boolean changed ) { for (IVariable var : fVariables.values()) { ((AbstractCVariable)var).setChanged( changed ); } } /* (non-Javadoc) * @see org.eclipse.cdt.debug.internal.core.model.AbstractCValue#dispose() */ public void dispose() { for (IVariable var : fVariables.values()) { ((AbstractCVariable)var).dispose(); } } /* (non-Javadoc) * @see org.eclipse.cdt.debug.internal.core.model.AbstractCValue#reset() */ protected void reset() { for (IVariable var : fVariables.values()) { ((AbstractCVariable)var).resetValue(); } } /* (non-Javadoc) * @see org.eclipse.cdt.debug.internal.core.model.AbstractCValue#preserve() */ protected void preserve() { resetStatus(); for (IVariable var : fVariables.values()) { ((AbstractCVariable)var).preserve(); } } /* (non-Javadoc) * @see org.eclipse.cdt.debug.core.model.ICValue#getType() */ public ICType getType() throws DebugException { if ( fType == null ) { synchronized( this ) { if ( fType == null ) { try { ICDIType cdiType = getCDIValue().getType(); if ( cdiType != null ) fType = new CType( cdiType ); } catch( CDIException e ) { targetRequestFailed( e.getMessage(), null ); } } } } return fType; } /* (non-Javadoc) * @see org.eclipse.debug.core.model.IValue#getReferenceTypeName() */ public String getReferenceTypeName() throws DebugException { ICType type = getType(); return ( type != null ) ? type.getName() : ""; //$NON-NLS-1$ } /** * Please note that this function returns the address of the array, not the * contents of the array, as long as the underlying ICDIArrayValue is an * instance of ICDIPointerValue. Otherwise, it returns an empty string. * * @see org.eclipse.debug.core.model.IValue#getValueString() */ public String getValueString() throws DebugException { if ( fCDIValue instanceof ICDIPointerValue ) { try { IAddressFactory factory = ((CDebugTarget)getDebugTarget()).getAddressFactory(); BigInteger pv = ((ICDIPointerValue)fCDIValue).pointerValue(); if ( pv == null ) return ""; //$NON-NLS-1$ IAddress address = factory.createAddress( pv ); if ( address == null ) return ""; //$NON-NLS-1$ CVariableFormat format = getParentVariable().getFormat(); if ( CVariableFormat.NATURAL.equals( format ) || CVariableFormat.HEXADECIMAL.equals( format ) ) return address.toHexAddressString(); if ( CVariableFormat.DECIMAL.equals( format ) ) return address.toString(); if ( CVariableFormat.BINARY.equals( format ) ) return address.toBinaryAddressString(); return null; } catch (CDIException e) { requestFailed( e.getMessage(), null ); } } return ""; //$NON-NLS-1$ } /* (non-Javadoc) * @see org.eclipse.debug.core.model.IValue#isAllocated() */ public boolean isAllocated() throws DebugException { return true; } /* (non-Javadoc) * @see org.eclipse.debug.core.model.IValue#getVariables() */ public IVariable[] getVariables() throws DebugException { return getVariables0( getInitialOffset(), getSize() ); } /* (non-Javadoc) * @see org.eclipse.debug.core.model.IValue#hasVariables() */ public boolean hasVariables() throws DebugException { return getSize() > 0; } /* (non-Javadoc) * @see org.eclipse.debug.core.model.IIndexedValue#getVariable(int) */ public IVariable getVariable( int offset ) throws DebugException { if ( offset >= getSize() ) { requestFailed( CoreModelMessages.getString( "CIndexedValue.0" ), null ); //$NON-NLS-1$ } return getVariables0( offset, 1 )[0]; } /* (non-Javadoc) * @see org.eclipse.debug.core.model.IIndexedValue#getVariables(int, int) */ public IVariable[] getVariables( int offset, int length ) throws DebugException { if ( offset >= getSize() ) { requestFailed( CoreModelMessages.getString( "CIndexedValue.1" ), null ); //$NON-NLS-1$ } if ( (offset + length - 1) >= getSize() ) { requestFailed( CoreModelMessages.getString( "CIndexedValue.2" ), null ); //$NON-NLS-1$ } return getVariables0( offset, length ); } /* (non-Javadoc) * @see org.eclipse.debug.core.model.IIndexedValue#getSize() */ public int getSize() throws DebugException { return getSize0(); } /* (non-Javadoc) * @see org.eclipse.debug.core.model.IIndexedValue#getInitialOffset() */ public int getInitialOffset() { return fOffset; } protected ICDIArrayValue getCDIValue() { return fCDIValue; } private int getPartitionSize( int index ) { int psize = getPreferredPartitionSize(); int size = getSize0(); int pcount = size/psize + 1; if ( pcount - 1 < index ) return 0; return ( pcount - 1 == index ) ? size % psize : psize; } private int getPartitionIndex( int offset ) { return offset / getPreferredPartitionSize(); } private int getPreferredPartitionSize() { return 100; } private IVariable[] getVariables0( int offset, int length ) throws DebugException { IVariable[] result = new IVariable[length]; int firstIndex = getPartitionIndex( offset ); int lastIndex = getPartitionIndex( offset + Math.max( length - 1, 0 ) ); for ( int i = firstIndex; i <= lastIndex; ++i ) { synchronized( this ) { if ( !isPartitionLoaded( i ) ) { loadPartition( i ); } } } for (int i = 0; i < length; i++) { result[i] = fVariables.get( offset + i ); } return result; } private boolean isPartitionLoaded( int index ) { return fVariables.containsKey(index * getPreferredPartitionSize()); } private void loadPartition( int index ) throws DebugException { int prefSize = getPreferredPartitionSize(); int psize = getPartitionSize( index ); ICDIVariable[] cdiVars = new ICDIVariable[0]; try { cdiVars = getCDIValue().getVariables( index * prefSize, psize ); } catch( CDIException e ) { requestFailed( e.getMessage(), null ); } for( int i = 0; i < cdiVars.length; ++i ) fVariables.put(i + index * prefSize, CVariableFactory.createLocalVariable( this, cdiVars[i] )); } private int getSize0() { return fSize; } }