private static MetricUnit[] GetMetricUnits(Type metricEnumType) { var result = new List <MetricUnit>(); var fields = EnumHelper.GetEnumValues(metricEnumType) .OrderBy(f => Convert.ToDouble(f.Value, CultureInfo.InvariantCulture)); MetricUnit previousUnit = null; foreach (var field in fields) { var unit = GetMetricUnit(field.UnderlyingField); if (previousUnit != null) { Code.AssertArgument( previousUnit.AppliesFrom < unit.AppliesFrom, nameof(metricEnumType), $"The applies from value of {metricEnumType.Name}.{unit.EnumValue} ({unit.AppliesFrom.ToInvariantString()}) " + $"should be greater than prev unit {metricEnumType.Name}.{previousUnit.EnumValue} value ({previousUnit.AppliesFrom.ToInvariantString()})"); } previousUnit = unit; result.Add(unit); } Code.AssertArgument( result.Count > 0, nameof(metricEnumType), $"The enum {metricEnumType} should be not empty."); return(result.ToArray()); }
/// <summary>Returns a <see cref="string"/> representation of min and max parts of a metric value.</summary> /// <param name="metricValues">Range of metric values.</param> /// <param name="metricUnit">The metric measurement unit.</param> /// <param name="minString">String representation of min part of a metric value.</param> /// <param name="maxString">String representation of max part of a metric value.</param> public static void GetMinMaxString( this MetricRange metricValues, [NotNull] MetricUnit metricUnit, out string minString, out string maxString) { metricValues = ToScaledValues(metricValues, metricUnit); var displayFormat = GetFormatForScaled(metricValues, metricUnit); minString = metricValues.Min.ToString(displayFormat, HostEnvironmentInfo.MainCultureInfo); maxString = metricValues.Max.ToString(displayFormat, HostEnvironmentInfo.MainCultureInfo); }
/// <summary>Returns a <see cref="string"/> representation of a metric value.</summary> /// <param name="metricValues">Range of metric values.</param> /// <param name="metricUnit">The metric measurement unit.</param> /// <returns>A <see cref="string"/> that represents the metric value.</returns> public static string ToString(this MetricRange metricValues, [NotNull] MetricUnit metricUnit) { metricValues = ToScaledValues(metricValues, metricUnit); var displayFormat = GetFormatForScaled(metricValues, metricUnit); var formattedValue = metricValues.ToString(displayFormat, HostEnvironmentInfo.MainCultureInfo); return((metricValues.IsEmpty || metricUnit.IsEmpty || string.IsNullOrEmpty(metricUnit.DisplayName)) ? formattedValue : formattedValue + " " + metricUnit.DisplayName); }
/// <summary>Creates a new metric range.</summary> /// <param name="min"> /// The minimum value. /// The <see cref="MetricRange.EmptyMetricValue"/> marks the range as unset but updateable during the annotation. /// Use <c>null</c> or <seealso cref="MetricRange.EmptyMetricValue"/> to set min value to negative infinity (ignored, essentially). /// </param> /// <param name="max"> /// The maximum value. /// Use <see cref="MetricRange"/> /// to mark the range as unset but updateable during the annotation. /// Use <c>null</c> or <seealso cref="MetricRange"/> to set max value to positive infinity (ignored, essentially). /// </param> /// <param name="metricUnit">The metric unit that was used to store metric range.</param> /// <returns>Metrics range.</returns> public static MetricRange CreateMetricRange(double?min, double?max, [NotNull] MetricUnit metricUnit) { var minValue = min ?? MetricRange.FromNegativeInfinity; var maxValue = max ?? MetricRange.ToPositiveInfinity; if (!metricUnit.IsEmpty) { minValue *= metricUnit.ScaleCoefficient; maxValue *= metricUnit.ScaleCoefficient; } return(new MetricRange(minValue, maxValue)); }
/// <summary> /// Determines whether the range contains another one. /// The check is performed using same rounding that will be used to store the <paramref name="metricValues"/>. /// </summary> /// <param name="metricValues">Range of metric values.</param> /// <param name="other">The metric range to check.</param> /// <param name="metricUnit"> /// The metric measurement unit that will be used to store the <paramref name="metricValues"/>. /// </param> /// <returns><c>true</c>, if the range contains another one.</returns> public static bool ContainsWithRounding( this MetricRange metricValues, MetricRange other, [NotNull] MetricUnit metricUnit) { var scaledMetricValues = metricValues.ToScaledValues(metricUnit); var scaledOtherMetricValues = other.ToScaledValues(metricUnit); var roundDigits = GetRoundingDigits(scaledMetricValues, metricUnit); scaledMetricValues = scaledMetricValues.Round(roundDigits); scaledOtherMetricValues = scaledOtherMetricValues.Round(roundDigits); return(scaledMetricValues.Contains(scaledOtherMetricValues)); }
/// <summary> /// Determines whether the range can be represented as a single point range /// (scaled and rounded min and max are the same). /// </summary> /// <param name="metricValues">Range of metric values.</param> /// <param name="metricUnit"> /// The metric measurement unit that will be used to store the <paramref name="metricValues"/>. /// </param> /// <returns><c>true</c>, if the range can be represented as a single point range.</returns> public static bool MinMaxAreSame(this MetricRange metricValues, [NotNull] MetricUnit metricUnit) { if (metricValues.IsEmpty) { return(true); } var scaledMetricValues = metricValues.ToScaledValues(metricUnit); var roundDigits = GetRoundingDigits(scaledMetricValues, metricUnit); scaledMetricValues = scaledMetricValues.Round(roundDigits); return(scaledMetricValues.Min.Equals(scaledMetricValues.Max)); }
/// <summary>Determines if the minimum metric value should be stored.</summary> /// <param name="metricRange">The metric range.</param> /// <param name="metricUnit">The metric unit.</param> /// <param name="singleValueMode">The single value treatment mode.</param> /// <returns><c>true</c>, if the minimum metric value should be stored.</returns> public static bool ShouldStoreMinMetricValue( this MetricRange metricRange, MetricUnit metricUnit, MetricSingleValueMode singleValueMode) { switch (singleValueMode) { case MetricSingleValueMode.FromZeroToMax: return(!metricRange.Min.Equals(0)); case MetricSingleValueMode.FromInfinityToMax: return(!double.IsInfinity(metricRange.Min)); case MetricSingleValueMode.BothMinAndMax: return(double.IsInfinity(metricRange.Min) || !metricRange.MinMaxAreSame(metricUnit)); default: throw CodeExceptions.UnexpectedArgumentValue(nameof(singleValueMode), singleValueMode); } }
/// <summary>Determines if the minimum metric value should be stored.</summary> /// <param name="metricRange">The metric range.</param> /// <param name="metricUnit">The metric unit.</param> /// <param name="defaultMinValue">>Min value to be used by default.</param> /// <returns><c>true</c>, if the minimum metric value should be stored.</returns> public static bool ShouldStoreMinMetricValue( this MetricRange metricRange, MetricUnit metricUnit, DefaultMinMetricValue defaultMinValue) { switch (defaultMinValue) { case DefaultMinMetricValue.Zero: return(!metricRange.Min.Equals(0)); case DefaultMinMetricValue.NegativeInfinity: return(!double.IsInfinity(metricRange.Min)); case DefaultMinMetricValue.SameAsMax: return(double.IsInfinity(metricRange.Min) || !metricRange.MinMaxAreSame(metricUnit)); default: throw CodeExceptions.UnexpectedArgumentValue(nameof(defaultMinValue), defaultMinValue); } }
private static int GetRoundingDigits(double scaledMetricValue, MetricUnit metricUnit) => metricUnit.RoundingDigits ?? GetRoundingDigits(scaledMetricValue);
private static double ToScaledValue(this double metricValue, [NotNull] MetricUnit metricUnit) => (double.IsNaN(metricValue) || metricUnit.IsEmpty) ? metricValue : metricValue / metricUnit.ScaleCoefficient;
private static MetricRange ToScaledValues(this MetricRange metricValues, MetricUnit metricUnit) => CreateMetricRange( metricValues.Min.ToScaledValue(metricUnit), metricValues.Max.ToScaledValue(metricUnit));
private static string GetFormatForScaled(MetricRange scaledMetricValues, MetricUnit metricUnit) => "F" + GetRoundingDigits(scaledMetricValues, metricUnit);
private static string GetFormatForScaled(double scaledMetricValue, MetricUnit metricUnit) => "F" + GetRoundingDigits(scaledMetricValue, metricUnit);
private static int GetRoundingDigits(MetricRange scaledMetricValues, MetricUnit metricUnit) => metricUnit.RoundingDigits ?? Math.Max( GetRoundingDigits(scaledMetricValues.Min), GetRoundingDigits(scaledMetricValues.Max));
/// <summary>Determines if the minimum metric value should be stored.</summary> /// <param name="metricRange">The metric range.</param> /// <param name="metricUnit">The metric unit.</param> /// <param name="metric">The metric information.</param> /// <returns><c>true</c>, if the minimum metric value should be stored.</returns> public static bool ShouldStoreMinMetricValue( this MetricRange metricRange, MetricUnit metricUnit, [NotNull] MetricInfo metric) => ShouldStoreMinMetricValue(metricRange, metricUnit, metric.SingleValueMode);
/// <summary>Determines if the minimum metric value should be stored.</summary> /// <param name="metricRange">The metric range.</param> /// <param name="metricUnit">The metric unit.</param> /// <param name="metric">The metric information.</param> /// <returns><c>true</c>, if the minimum metric value should be stored.</returns> public static bool ShouldStoreMinMetricValue( this MetricRange metricRange, MetricUnit metricUnit, [NotNull] MetricInfo metric) => ShouldStoreMinMetricValue(metricRange, metricUnit, metric.DefaultMinValue);