JD2022-TU1/main/extern/ProfileEventViewer4/Utils.cs

405 lines
No EOL
14 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Time = System.Double;
namespace ProfileEventViewer
{
public class Filters
{
public string OriginalFilter { get; set; }
private List<string> m_Filters = new List<string>();
public bool IsValid { get { return m_Filters.Count != 0; } }
public Filters()
{
SetFilter(string.Empty);
}
public void SetFilter(string filter)
{
m_Filters.Clear();
m_Filters.AddRange(ParseFilter(filter).Select(f => f.ToUpperInvariant()));
OriginalFilter = filter;
}
private IEnumerable<string> ParseFilter(string filter)
{
int lastIndex = 0;
bool inQuotes = false;
for (int index = 0; index < filter.Length; ++index)
{
char c = filter[index];
if (c == '"')
{
if (lastIndex < index - 1)
{
string substr = filter.Substring(lastIndex, index - lastIndex);
if (inQuotes)
yield return substr;
else
foreach (string subFilter in substr.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries))
yield return subFilter;
}
lastIndex = index + 1;
inQuotes = !inQuotes;
}
}
if (lastIndex != filter.Length)
{
string substr = filter.Substring(lastIndex, filter.Length - lastIndex);
if (inQuotes)
yield return substr;
else
foreach (string subFilter in substr.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries))
yield return subFilter;
}
}
public bool IsAllowed(string str)
{
string upperStr = str.ToUpperInvariant();
return m_Filters.Any(filter => upperStr.Contains(filter));
}
}
public class ClockTime
{
private List<TimeExtent> m_TimeExtents = new List<TimeExtent>();
private List<Time> m_Mins = new List<Time>();
private List<Time> m_Maxs = new List<Time>();
private struct TimeExtentExtremum
{
public Time Time;
public bool IsMinExtent;
}
private class MinExtentComparer : IComparer<TimeExtent>
{
public int Compare(TimeExtent x, TimeExtent y) { return Math.Sign(x.Min - y.Min); }
}
private class MaxExtentComparer : IComparer<TimeExtent>
{
public int Compare(TimeExtent x, TimeExtent y) { return Math.Sign(x.Max - y.Max); }
}
private class MinMaxExtentComparer : IComparer<TimeExtent>
{
public int Compare(TimeExtent x, TimeExtent y) { return Math.Sign(x.Max - y.Min); }
}
private class MaxMinExtentComparer : IComparer<TimeExtent>
{
public int Compare(TimeExtent x, TimeExtent y) { return Math.Sign(x.Min - y.Max); }
}
public void Merge(ClockTime clockTime)
{
foreach (TimeExtent timeExtent in clockTime.m_TimeExtents)
Merge(timeExtent.Min, timeExtent.Max);
}
public void Merge(Time minExtent, Time maxExtent)
{
if (maxExtent <= minExtent)
System.Diagnostics.Debugger.Break();
m_Mins.Add(minExtent);
m_Maxs.Add(maxExtent);
}
// Returns indices as List<T>.BinarySearch would return them.
private void GetMinAndMaxInsertionIndicesFromExtent(TimeExtent extent, out int outMinIndex, out int outMaxIndex)
{
int minMaxIndex = m_TimeExtents.BinarySearch(extent, new MinMaxExtentComparer());
int positiveMinMaxIndex = (minMaxIndex >= 0 ? minMaxIndex : ~minMaxIndex);
int minIndex = m_TimeExtents.BinarySearch(positiveMinMaxIndex, m_TimeExtents.Count - positiveMinMaxIndex, extent, new MinExtentComparer());
int maxIndex = m_TimeExtents.BinarySearch(positiveMinMaxIndex, m_TimeExtents.Count - positiveMinMaxIndex, extent, new MaxExtentComparer());
int positiveMaxIndex = (maxIndex >= 0 ? maxIndex : ~maxIndex);
int maxMinIndex = m_TimeExtents.BinarySearch(positiveMaxIndex, m_TimeExtents.Count - positiveMaxIndex, extent, new MaxMinExtentComparer());
if (minIndex >= 0)
outMinIndex = minIndex;
else if (minMaxIndex >= 0)
outMinIndex = minMaxIndex;
else if (minIndex == minMaxIndex)
outMinIndex = minMaxIndex;
else
outMinIndex = positiveMinMaxIndex;
if (maxIndex >= 0)
outMaxIndex = maxIndex;
else if (maxMinIndex >= 0)
outMaxIndex = maxMinIndex;
else if (maxIndex == maxMinIndex)
outMaxIndex = maxIndex;
else
outMaxIndex = positiveMaxIndex;
if ((outMinIndex >= 0 ? outMinIndex : ~outMinIndex) > (outMaxIndex >= 0 ? outMaxIndex : ~outMaxIndex))
System.Diagnostics.Debugger.Break();
}
public void CoalesceResults()
{
// It's faster to use unsorted lists to gather times and then sort them rather than sorting at insertion time (either using lists or sorted containers)
// Also, using a single List<TimeExtentExtremum> is also slower, because sorting it takes more time (and I'm not sure why! (but it must have something to do with the complex sorting condition))
m_Mins.Sort();
m_Maxs.Sort();
List<TimeExtentExtremum> timeExtentPoints = new List<TimeExtentExtremum>(m_Mins.Count + m_Maxs.Count);
// Merge them!
var minIt = m_Mins.GetEnumerator();
var maxIt = m_Maxs.GetEnumerator();
bool minIsValid = minIt.MoveNext();
bool maxIsValid = maxIt.MoveNext();
while (minIsValid && maxIsValid)
{
if (minIt.Current <= maxIt.Current)
{
timeExtentPoints.Add(new TimeExtentExtremum() { Time = minIt.Current, IsMinExtent = true });
minIsValid = minIt.MoveNext();
}
else
{
timeExtentPoints.Add(new TimeExtentExtremum() { Time = maxIt.Current, IsMinExtent = false });
maxIsValid = maxIt.MoveNext();
}
}
// Ignore remaining mins, add remaining maxs
if (maxIsValid)
{
do
{
timeExtentPoints.Add(new TimeExtentExtremum() { Time = maxIt.Current, IsMinExtent = false });
} while (maxIt.MoveNext());
}
Time minValue = Time.MaxValue;
int count = 0;
int index = timeExtentPoints.FindIndex(p => p.IsMinExtent);
if (index >= 0)
{
for (; index < timeExtentPoints.Count; ++index)
{
TimeExtentExtremum p = timeExtentPoints[index];
if (p.IsMinExtent)
{
if (++count == 1)
minValue = p.Time;
}
else
{
if (--count == 0 && minValue != p.Time)
m_TimeExtents.Add(new TimeExtent() { Min = minValue, Max = p.Time });
}
}
}
m_Mins.Clear();
m_Maxs.Clear();
#if DEBUG
// For debugging purposes... but it is pretty slow
for (int i = 1; i < m_TimeExtents.Count; ++i)
{
if (m_TimeExtents[i].Min <= m_TimeExtents[i - 1].Min ||
m_TimeExtents[i].Max <= m_TimeExtents[i - 1].Max ||
m_TimeExtents[i].Min <= m_TimeExtents[i - 1].Max ||
m_TimeExtents[i].Max <= m_TimeExtents[i - 1].Min)
System.Diagnostics.Debugger.Break();
}
#endif
}
public Time GetTime()
{
return m_TimeExtents.Aggregate(0, (Time t, TimeExtent extent) => t + extent.Length);
}
public Time GetTimeWithinRange(Time start, Time end)
{
return GetClockTimeWithinRange(start, end).GetTime();
}
public ClockTime GetClockTimeWithinRange(Time start, Time end)
{
ClockTime newClockTime = new ClockTime();
TimeExtent extent = new TimeExtent { Min = start, Max = end };
int outMinIndex, outMaxIndex;
GetMinAndMaxInsertionIndicesFromExtent(extent, out outMinIndex, out outMaxIndex);
int minIndex = (outMinIndex >= 0 ? outMinIndex : ~outMinIndex);
int maxIndex = (outMaxIndex >= 0 ? outMaxIndex : ~outMaxIndex - 1);
if (minIndex > maxIndex)
return newClockTime;
List<TimeExtent> timeExtents = m_TimeExtents.GetRange(minIndex, maxIndex - minIndex + 1);
if (timeExtents[0].Min < start)
timeExtents[0] = new TimeExtent() { Min = start, Max = timeExtents[0].Max };
if (timeExtents[timeExtents.Count - 1].Max > end)
timeExtents[timeExtents.Count - 1] = new TimeExtent() { Min = timeExtents[timeExtents.Count - 1].Min, Max = end };
newClockTime.m_TimeExtents = timeExtents;
return newClockTime;
}
}
public class ListViewInfo
{
public string ProfileName { get; set; }
public UInt32 ProfileId; // Not a property: not serialized.
public Time TotalTime { get; set; }
public UInt32 CallCount { get; set; }
public Time MeanTime { get { return TotalTime / CallCount; } }
public Time ClockTime { get; set; } // Cached value of the ClockTimeObject
public Time MinTimeExtent { get; set; }
public Time MaxTimeExtent { get; set; }
public Time MinTime { get; set; }
public Time MaxTime { get; set; }
// This is not a property so it is not serialized.
private ClockTime m_ClockTimeObject = null;
public ClockTime GetClockTimeObject() { return m_ClockTimeObject; }
public void SetClockTimeObject(ClockTime clockTimeObject) { m_ClockTimeObject = clockTimeObject; }
}
public class SortInfo
{
public bool Ascending { get; set; }
public int Column { get; set; }
}
public class ListViewCache
{
private List<ListViewItem> m_ListViewItems = new List<ListViewItem>();
private int m_StartIndex = -1;
public bool IsIndexInCache(int index)
{
int cacheIndex = index - m_StartIndex;
return (cacheIndex >= 0 && cacheIndex < m_ListViewItems.Count);
}
public bool IsRangeInCache(int startIndex, int endIndex)
{
return (startIndex >= m_StartIndex && endIndex <= m_StartIndex + m_ListViewItems.Count);
}
public ListViewItem GetListViewItem(int index)
{
return m_ListViewItems[index - m_StartIndex];
}
public void Clear()
{
m_StartIndex = -1;
m_ListViewItems.Clear();
}
public void Populate(IEnumerable<ListViewItem> itemsToCache, int startIndex)
{
Clear();
m_StartIndex = startIndex;
m_ListViewItems.AddRange(itemsToCache);
}
}
// Inspired by http://www.codeproject.com/Articles/42068/Merge-Sort
public class MergeSort
{
public static void Sort<T>(IList<T> list) where T : IComparable
{
Sort(list, (T a, T b) => a.CompareTo(b));
}
public static void Sort<T>(IList<T> list, Comparison<T> comparison)
{
int count = list.Count;
RecursiveMergeSort(list, count, comparison);
}
private static void RecursiveMergeSort<T>(IList<T> toSort, int n, Comparison<T> comparison)
{
// Recursion stop condition
if (n == 2)
{
int compareValue = comparison(toSort[0], toSort[1]);
if (compareValue > 0)
{
T tempT = toSort[0];
toSort[0] = toSort[1];
toSort[1] = tempT;
}
}
else if (n > 2)
{
int m = n / 2;
IList<T> leftList = new List<T>((n / 2) + 2);
IList<T> rightList = new List<T>((n / 2) + 2);
// Initialize the 2 Sub-Arrays (The first relevant values)
for (int i = 0; i < m; i = i + 1)
leftList.Add(toSort[i]);
for (int j = m; j < n; j++)
rightList.Add(toSort[j]);
// 2 Recursive Calling, Sorting Sub-Arrays
RecursiveMergeSort(leftList, m, comparison);
RecursiveMergeSort(rightList, n - m, comparison);
// Merging the Sorted Sub-Arrays into the main Array
int p = 0;
int q = 0;
int k = 0;
for (; k < n && p < m && q < (n - m); ++k)
{
if (comparison(leftList[p], rightList[q]) <= 0)
toSort[k] = leftList[p++];
else
toSort[k] = rightList[q++];
}
if (p < m)
{
for (; k < n; ++k, ++p)
toSort[k] = leftList[p];
}
else
{
for (; k < n; ++k, ++q)
toSort[k] = rightList[q];
}
System.Diagnostics.Debug.Assert(k == n);
System.Diagnostics.Debug.Assert(p == m);
System.Diagnostics.Debug.Assert(q == (n - m));
}
}
}
}