using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Serialization;
namespace OpenCover.Framework.Model
{
///
/// An instrumentable point
///
public class InstrumentationPoint
{
private static int _instrumentPoint;
private static readonly object LockObject = new object();
private static readonly List InstrumentPoints;
static InstrumentationPoint()
{
_instrumentPoint = 0;
InstrumentPoints = new List(8192) {null};
}
internal static void Clear()
{
InstrumentPoints.Clear();
InstrumentPoints.Add(null);
_instrumentPoint = 0;
}
internal static void ResetAfterLoading()
{
var points = InstrumentPoints
.Where(x => x != null)
.GroupBy(x => x.UniqueSequencePoint)
.Select(g => g.OrderBy(x => x.OrigSequencePoint).First())
.ToList();
var max = (int)points.Max(x => x.UniqueSequencePoint);
InstrumentPoints.Clear();
InstrumentPoints.Add(null);
for (var i = 1; i <= max; i++)
{
var point = new SequencePoint();
InstrumentPoints[i] = point;
point.UniqueSequencePoint = (uint)i;
}
foreach (var instrumentationPoint in points)
{
InstrumentPoints[(int)instrumentationPoint.UniqueSequencePoint] = instrumentationPoint;
}
_instrumentPoint = max;
}
///
/// Return the number of visit points
///
public static int Count {
get { return InstrumentPoints.Count; }
}
///
/// Get the number of recorded visit points for this identifier
///
/// the sequence point identifier - NOTE 0 is not used
public static int GetVisitCount(uint spid)
{
return InstrumentPoints[(int) spid].VisitCount;
}
///
/// Add a number of recorded visit ppints against this identifier
///
/// the sequence point identifier - NOTE 0 is not used
/// the id of a tracked method - Note 0 means no method currently tracking
/// the number of visit points to add
public static bool AddVisitCount(uint spid, uint trackedMethodId, int amount)
{
if (spid != 0 && spid < InstrumentPoints.Count)
{
var point = InstrumentPoints[(int) spid];
point.VisitCount += amount;
if (point.VisitCount < 0)
{
point.VisitCount = int.MaxValue;
}
if (trackedMethodId != 0)
{
AddOrUpdateTrackingPoint(trackedMethodId, amount, point);
}
return true;
}
return false;
}
private static void AddOrUpdateTrackingPoint(uint trackedMethodId, int amount, InstrumentationPoint point)
{
point._tracked = point._tracked ?? new List();
var tracked = point._tracked.Find(x => x.UniqueId == trackedMethodId);
if (tracked == null)
{
tracked = new TrackedMethodRef {UniqueId = trackedMethodId, VisitCount = amount};
point._tracked.Add(tracked);
}
else
{
tracked.VisitCount += amount;
if (tracked.VisitCount < 0)
tracked.VisitCount = int.MaxValue;
}
}
private List _tracked;
///
/// Initialise
///
public InstrumentationPoint()
{
lock (LockObject)
{
UniqueSequencePoint = (uint)++_instrumentPoint;
InstrumentPoints.Add(this);
OrigSequencePoint = UniqueSequencePoint;
}
}
///
/// Store the number of visits
///
[XmlAttribute("vc")]
public int VisitCount { get; set; }
///
/// A unique number
///
[XmlAttribute("uspid")]
public UInt32 UniqueSequencePoint { get; set; }
///
/// An order of the point within the method
///
[XmlAttribute("ordinal")]
public UInt32 Ordinal { get; set; }
///
/// The IL offset of the point
///
[XmlAttribute("offset")]
public int Offset { get; set; }
///
/// Used to hide an instrumentation point
///
[XmlIgnore]
public bool IsSkipped { get; set; }
///
/// The list of tracked methods
///
public TrackedMethodRef[] TrackedMethodRefs
{
get
{
if (_tracked != null)
{
return _tracked.ToArray();
}
return null;
}
set
{
_tracked = null;
if (value == null)
return;
_tracked = new List(value);
}
}
///
///
///
[XmlIgnore]
public UInt32 OrigSequencePoint { get; set; }
}
}