Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,36 @@ public static IProjection<int, TimeRange> Create(IProjection<int, TimeRange> tim
return (IProjection<int, TimeRange>)instance;
}

/// <summary>
/// Create a <see cref="ResourceTimeRange"/> projection that is clipped to a
/// <see cref="VisibleDomainRegionContainer"/>.
/// See also <seealso cref="IVisibleDomainSensitiveProjection"/>.
/// </summary>
/// <param name="resourceTimeRangeProjection">
/// Original projection.
/// </param>
/// <returns>
/// A visible domain sensitive projection.
/// </returns>
public static IProjection<int, ResourceTimeRange> Create(IProjection<int, ResourceTimeRange> resourceTimeRangeProjection)
{
Guard.NotNull(resourceTimeRangeProjection, nameof(resourceTimeRangeProjection));

var typeArgs = new[]
{
resourceTimeRangeProjection.GetType(),
};

var constructorArgs = new object[]
{
resourceTimeRangeProjection,
};

var type = typeof(ClipTimeToVisibleResourceTimeRangeDomainColumnGenerator<>).MakeGenericType(typeArgs);
var instance = Activator.CreateInstance(type, constructorArgs);
return (IProjection<int, ResourceTimeRange>)instance;
}

/// <summary>
/// Creates a new percent projection that is defined by the current viewport.
/// </summary>
Expand Down Expand Up @@ -101,6 +131,34 @@ public static IProjection<int, TimeRange> CreatePercent(IProjection<int, TimeRan
return (IProjection<int, TimeRange>)instance;
}

/// <summary>
/// Creates a new percent projection that is defined by the current viewport.
/// </summary>
/// <param name="resourceTimeRangeColumn">
/// Original projection.
/// </param>
/// <returns>
/// A viewport sensitive projection.
/// </returns>
public static IProjection<int, ResourceTimeRange> CreatePercent(IProjection<int, ResourceTimeRange> resourceTimeRangeColumn)
{
Guard.NotNull(resourceTimeRangeColumn, nameof(resourceTimeRangeColumn));

var typeArgs = new[]
{
resourceTimeRangeColumn.GetType(),
};

var constructorArgs = new object[]
{
resourceTimeRangeColumn,
};

var type = typeof(ClipTimeToVisibleResourceTimeRangePercentColumnGenerator<>).MakeGenericType(typeArgs);
var instance = Activator.CreateInstance(type, constructorArgs);
return (IProjection<int, ResourceTimeRange>)instance;
}

[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
private struct ClipTimeToVisibleTimestampDomainColumnGenerator<TGenerator>
: IProjection<int, Timestamp>,
Expand Down Expand Up @@ -228,6 +286,72 @@ public bool NotifyVisibleDomainChanged(IVisibleDomainRegion visibleDomain)
public bool DependsOnVisibleDomain => true;
}

[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
private struct ClipTimeToVisibleResourceTimeRangeDomainColumnGenerator<TGenerator>
: IProjection<int, ResourceTimeRange>,
IVisibleDomainSensitiveProjection
where TGenerator : IProjection<int, ResourceTimeRange>
{
internal TGenerator Generator { get; }

internal VisibleDomainRegionContainer VisibleDomainContainer { get; }

public ClipTimeToVisibleResourceTimeRangeDomainColumnGenerator(TGenerator resourceTimeRangeGenerator)
{
this.Generator = resourceTimeRangeGenerator;
this.VisibleDomainContainer = new VisibleDomainRegionContainer();
}

// IProjection<int, Timestamp>
public ResourceTimeRange this[int value]
{
get
{
TimeRange visibleDomain = this.VisibleDomainContainer.VisibleDomain;

ResourceTimeRange resourceTimeRange = this.Generator[value];

resourceTimeRange.StartTime = ClipTimestampToVisibleDomain(resourceTimeRange.StartTime, visibleDomain);
resourceTimeRange.EndTime = ClipTimestampToVisibleDomain(resourceTimeRange.EndTime, visibleDomain);

return resourceTimeRange;
}
}

public Type SourceType
{
get
{
return typeof(int);
}
}

public Type ResultType
{
get
{
return typeof(ResourceTimeRange);
}
}

public object Clone()
{
var result = new ClipTimeToVisibleResourceTimeRangeDomainColumnGenerator<TGenerator>(
VisibleDomainSensitiveProjection.CloneIfVisibleDomainSensitive(this.Generator));
return result;
}


public bool NotifyVisibleDomainChanged(IVisibleDomainRegion visibleDomain)
{
this.VisibleDomainContainer.VisibleDomainRegion = visibleDomain;
VisibleDomainSensitiveProjection.NotifyVisibleDomainChanged(this.Generator, visibleDomain);
return true;
}

public bool DependsOnVisibleDomain => true;
}

private struct ClipTimeToVisibleTimeRangePercentColumnGenerator<TGenerator>
: IProjection<int, TimeRange>,
IVisibleDomainSensitiveProjection,
Expand Down Expand Up @@ -319,6 +443,98 @@ public string Format(string format, object arg, IFormatProvider formatProvider)
}
}
}

private struct ClipTimeToVisibleResourceTimeRangePercentColumnGenerator<TGenerator>
: IProjection<int, ResourceTimeRange>,
IVisibleDomainSensitiveProjection,
IFormatProvider
where TGenerator : IProjection<int, ResourceTimeRange>
{
private readonly ClipTimeToVisibleResourceTimeRangeDomainColumnGenerator<TGenerator> resourceTimeRangeColumnGenerator;

// IFormatProvider returns an object - cannot return 'this' struct.
// So implement ICustomFormatter in a private class and return that object.
//
private readonly ClipTimeToVisibleResourceTimeRangePercentFormatProvider customFormatter;

public ClipTimeToVisibleResourceTimeRangePercentColumnGenerator(TGenerator timeRangeGenerator)
{
var internalGenerator = new ClipTimeToVisibleResourceTimeRangeDomainColumnGenerator<TGenerator>(timeRangeGenerator);
this.resourceTimeRangeColumnGenerator = internalGenerator;

this.customFormatter =
new ClipTimeToVisibleResourceTimeRangePercentFormatProvider(() => internalGenerator.VisibleDomainContainer.VisibleDomain.Duration);
}

public ResourceTimeRange this[int value] => this.resourceTimeRangeColumnGenerator[value];

public Type SourceType => typeof(int);

public Type ResultType => typeof(ResourceTimeRange);

public bool DependsOnVisibleDomain => true;

public object GetFormat(Type formatType)
{
return (formatType == typeof(ResourceTimeRange) ||
formatType == typeof(TimestampDelta)) ? this.customFormatter : null;
}

public object Clone()
{
var result = new ClipTimeToVisibleResourceTimeRangePercentColumnGenerator<TGenerator>(
VisibleDomainSensitiveProjection.CloneIfVisibleDomainSensitive(this.resourceTimeRangeColumnGenerator.Generator));
return result;
}

public bool NotifyVisibleDomainChanged(IVisibleDomainRegion visibleDomain)
{
this.resourceTimeRangeColumnGenerator.NotifyVisibleDomainChanged(visibleDomain);
return true;
}

private class ClipTimeToVisibleResourceTimeRangePercentFormatProvider
: ICustomFormatter
{
private readonly Func<TimestampDelta> getVisibleDomainDuration;

public ClipTimeToVisibleResourceTimeRangePercentFormatProvider(Func<TimestampDelta> getVisibleDomainDuration)
{
Guard.NotNull(getVisibleDomainDuration, nameof(getVisibleDomainDuration));

this.getVisibleDomainDuration = getVisibleDomainDuration;
}

public string Format(string format, object arg, IFormatProvider formatProvider)
{
if (arg == null)
{
return string.Empty;
}

TimestampDelta numerator;
if (arg is ResourceTimeRange)
{
numerator = ((ResourceTimeRange)arg).Duration;
}
else if (arg is TimestampDelta)
{
numerator = (TimestampDelta)arg;
}
else
{
throw new FormatException();
}

TimestampDelta visibleDomainDuration = getVisibleDomainDuration();
double percent = (visibleDomainDuration != TimestampDelta.Zero) ?
(100.0 * ((double)numerator.ToNanoseconds) / (visibleDomainDuration.ToNanoseconds)) :
100.0;

return percent.ToString(format, formatProvider);
}
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,54 @@ var columnRelativeToVisibleDomain
return columnRelativeToVisibleDomain;
}

/// <summary>
/// Creates a projection that returns the percentage of the visible time consumed by this
/// <see cref="TimeRange"/>.
/// </summary>
/// <param name="timeRangeColumn">
/// Time range.
/// </param>
/// <returns>
/// Percent of time consumed by the given time range in a given visible domain.
/// </returns>
public static IProjection<int, double> Create(
IProjection<int, TimeRange> timeRangeColumn)
{
Guard.NotNull(timeRangeColumn, nameof(timeRangeColumn));

var aggregateRowsInVisibleDomainColumn
= Projection.AggregateInVisibleDomain<TimeRange, TimestampDelta>(timeRangeColumn);

var columnRelativeToVisibleDomain
= Percent.Create(timeRangeColumn.Compose(timeRange => timeRange.Duration), aggregateRowsInVisibleDomainColumn);

return columnRelativeToVisibleDomain;
}

/// <summary>
/// Creates a projection that returns the percentage of the visible time consumed by this
/// <see cref="ResourceTimeRange"/>.
/// </summary>
/// <param name="resourceTimeRangeColumn">
/// Resource time range.
/// </param>
/// <returns>
/// Percent of time consumed by the given resource time range in a given visible domain.
/// </returns>
public static IProjection<int, double> Create(
IProjection<int, ResourceTimeRange> resourceTimeRangeColumn)
{
Guard.NotNull(resourceTimeRangeColumn, nameof(resourceTimeRangeColumn));

var aggregateRowsInVisibleDomainColumn
= Projection.AggregateInVisibleDomain<ResourceTimeRange, TimestampDelta>(resourceTimeRangeColumn);

var columnRelativeToVisibleDomain
= Percent.Create(resourceTimeRangeColumn.Compose(resourceTimeRange => resourceTimeRange.Duration), aggregateRowsInVisibleDomainColumn);

return columnRelativeToVisibleDomain;
}

/// <summary>
/// Creates a projection that maps a percentage relative to an entire domain to a percentage
/// relative to the current visible domain.
Expand Down
Loading