blob: 540756cd43b9a4e7fe57f48ed2051f1d1d55fea6 [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: CoverageData.java,v 1.1.1.1 2004/05/09 16:57:31 vlad_r Exp $
*/
package com.vladium.emma.data;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import com.vladium.util.asserts.$assert;
// ----------------------------------------------------------------------------
/**
* @author Vlad Roubtsov, (C) 2003
*/
final class CoverageData implements ICoverageData, Cloneable
{
// public: ................................................................
// TODO: duplicate issue
public Object lock ()
{
return m_coverageMap;
}
public ICoverageData shallowCopy ()
{
final CoverageData _clone;
try
{
_clone = (CoverageData) super.clone ();
}
catch (CloneNotSupportedException cnse)
{
throw new Error (cnse.toString ());
}
final HashMap _coverageMap;
synchronized (lock ())
{
_coverageMap = (HashMap) m_coverageMap.clone ();
}
_clone.m_coverageMap = _coverageMap;
return _clone;
}
public int size ()
{
return m_coverageMap.size ();
}
public DataHolder getCoverage (final ClassDescriptor cls)
{
if (cls == null) throw new IllegalArgumentException ("null input: cls");
return (DataHolder) m_coverageMap.get (cls.getClassVMName ());
}
public void addClass (final boolean [][] coverage, final String classVMName, final long stamp)
{
m_coverageMap.put (classVMName, new DataHolder (coverage, stamp));
}
// IMergeable:
public boolean isEmpty ()
{
return m_coverageMap.isEmpty ();
}
/*
* This method is not MT-safe wrt addClass() etc.
*
* note: rhs entries override current entries if they have different stamps;
* otherwise, the data is merged
*/
public IMergeable merge (final IMergeable rhs)
{
if ((rhs == null) || rhs.isEmpty () || (rhs == this))
return this;
else
{
final CoverageData rhscdata = (CoverageData) rhs; // TODO: redesign so that the cast is not necessary
final Map rhscoverageData = rhscdata.m_coverageMap;
for (Iterator entries = rhscoverageData.entrySet ().iterator (); entries.hasNext (); )
{
final Map.Entry entry = (Map.Entry) entries.next ();
final String classVMName = (String) entry.getKey ();
final DataHolder rhsdata = (DataHolder) entry.getValue ();
// [assertion: rhsdata != null]
final DataHolder data = (DataHolder) m_coverageMap.get (classVMName);
if (data == null)
m_coverageMap.put (classVMName, rhsdata);
else
{
if (rhsdata.m_stamp != data.m_stamp)
m_coverageMap.put (classVMName, rhsdata);
else // merge two runtime profiles
{
final boolean [][] rhscoverage = rhsdata.m_coverage;
final boolean [][] coverage = data.m_coverage;
// [assertion: both coverage and rhscoverage aren't null]
if ($assert.ENABLED) $assert.ASSERT (coverage.length == rhscoverage.length, "coverage.length [" + coverage.length + "] != rhscoverage.length [" + rhscoverage.length + "]");
for (int m = 0, mLimit = coverage.length; m < mLimit; ++ m)
{
final boolean [] rhsmcoverage = rhscoverage [m];
final boolean [] mcoverage = coverage [m];
if (mcoverage == null)
{
if ($assert.ENABLED) $assert.ASSERT (rhsmcoverage == null, "mcoverage == null but rhsmcoverage != null");
// [nothing to merge]
}
else
{
if ($assert.ENABLED) $assert.ASSERT (rhsmcoverage != null, "mcoverage != null but rhsmcoverage == null");
if ($assert.ENABLED) $assert.ASSERT (mcoverage.length == rhsmcoverage.length, "mcoverage.length [" + mcoverage.length + "] != rhsmcoverage.length [" + rhsmcoverage.length + "]");
for (int b = 0, bLimit = mcoverage.length; b < bLimit; ++ b)
{
if (rhsmcoverage [b]) mcoverage [b] = true;
}
}
}
}
}
}
return this;
}
}
// protected: .............................................................
// package: ...............................................................
CoverageData ()
{
m_coverageMap = new HashMap ();
}
static CoverageData readExternal (final DataInput in)
throws IOException
{
final int size = in.readInt ();
final HashMap coverageMap = new HashMap (size);
for (int i = 0; i < size; ++ i)
{
final String classVMName = in.readUTF ();
final long stamp = in.readLong ();
final int length = in.readInt ();
final boolean [][] coverage = new boolean [length][];
for (int c = 0; c < length; ++ c)
{
coverage [c] = DataFactory.readBooleanArray (in);
}
coverageMap.put (classVMName, new DataHolder (coverage, stamp));
}
return new CoverageData (coverageMap);
}
static void writeExternal (final CoverageData cdata, final DataOutput out)
throws IOException
{
final Map coverageMap = cdata.m_coverageMap;
final int size = coverageMap.size ();
out.writeInt (size);
final Iterator entries = coverageMap.entrySet ().iterator ();
for (int i = 0; i < size; ++ i)
{
final Map.Entry entry = (Map.Entry) entries.next ();
final String classVMName = (String) entry.getKey ();
final DataHolder data = (DataHolder) entry.getValue ();
final boolean [][] coverage = data.m_coverage;
out.writeUTF (classVMName);
out.writeLong (data.m_stamp);
final int length = coverage.length;
out.writeInt (length);
for (int c = 0; c < length; ++ c)
{
DataFactory.writeBooleanArray (coverage [c], out);
}
}
}
// private: ...............................................................
private CoverageData (final HashMap coverageMap)
{
if ($assert.ENABLED) $assert.ASSERT (coverageMap != null, "coverageMap is null");
m_coverageMap = coverageMap;
}
private /*final*/ HashMap /* String(classVMName) -> DataHolder */ m_coverageMap; // never null
} // end of class
// ----------------------------------------------------------------------------