//****************************************************************************************************** // Range.cs - Gbtc // // Copyright © 2015, Grid Protection Alliance. All Rights Reserved. // // Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See // the NOTICE file distributed with this work for additional information regarding copyright ownership. // The GPA licenses this file to you under the MIT License (MIT), the "License"; you may // not use this file except in compliance with the License. You may obtain a copy of the License at: // // http://opensource.org/licenses/MIT // // Unless agreed to in writing, the subject software distributed under the License is distributed on an // "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the // License for the specific language governing permissions and limitations. // // Code Modification History: // ---------------------------------------------------------------------------------------------------- // 06/30/2015 - Stephen C. Wills // Generated original version of source code. // //****************************************************************************************************** using System; using System.Collections.Generic; using System.Linq; namespace GSF { /// /// Represents a range of values with a start and end value. /// public class Range { #region [ Members ] // Fields private readonly T m_start; private readonly T m_end; #endregion #region [ Constructors ] /// /// Creates a new instance of the class using the default comparer. /// /// The start value of the range. /// The end value of the range. public Range(T start, T end) { m_start = start; m_end = end; } #endregion #region [ Properties ] /// /// Gets the start value of the range. /// public T Start { get { return m_start; } } /// /// Gets the end value of the range. /// public T End { get { return m_end; } } #endregion #region [ Methods ] /// /// Determines whether the range overlaps with the given range. /// /// The range to be compared with. /// True if the ranges overlap; false otherwise. public bool Overlaps(Range range) { return Overlaps(range, Comparer.Default); } /// /// Determines whether the range overlaps with the given range. /// /// The range to be compared with. /// The comparer used to compare objects of type . /// True if the ranges overlap; false otherwise. public bool Overlaps(Range range, IComparer comparer) { return Overlaps(range, comparer.Compare); } /// /// Determines whether the range overlaps with the given range. /// /// The range to be compared with. /// The comparison used to compare objects of type . /// True if the ranges overlap; false otherwise. public bool Overlaps(Range range, Comparison comparison) { return comparison(m_start, range.m_end) <= 0 && comparison(range.m_start, m_end) <= 0; } /// /// Merges two ranges into one range that fully encompasses both ranges. /// /// The range to be merged with this one. /// The range that fully encompasses the merged ranges. public Range Merge(Range range) { return Merge(range, Comparer.Default); } /// /// Merges two ranges into one range that fully encompasses both ranges. /// /// The range to be merged with this one. /// The comparer used to compare objects of type . /// The range that fully encompasses the merged ranges. public Range Merge(Range range, IComparer comparer) { return Merge(range, comparer.Compare); } /// /// Merges two ranges into one range that fully encompasses both ranges. /// /// The range to be merged with this one. /// The comparison used to compare objects of type . /// The range that fully encompasses the merged ranges. public Range Merge(Range range, Comparison comparison) { T start = comparison(m_start, range.m_start) <= 0 ? m_start : range.m_start; T end = comparison(m_end, range.m_end) >= 0 ? m_end : range.m_end; return new Range(start, end); } #endregion #region [ Static ] // Static Methods /// /// Merges all ranges in a collection of ranges. /// /// The collection of ranges to be merged. /// A range that is the result of merging all ranges in the collection. public static Range Merge(IEnumerable> ranges) { return Merge(ranges, Comparer.Default); } /// /// Merges all ranges in a collection of ranges. /// /// The collection of ranges to be merged. /// The comparer used to compare objects of type . /// A range that is the result of merging all ranges in the collection. public static Range Merge(IEnumerable> ranges, Comparer comparer) { return Merge(ranges, comparer.Compare); } /// /// Merges all ranges in a collection of ranges. /// /// The collection of ranges to be merged. /// The comparison used to compare objects of type . /// A range that is the result of merging all ranges in the collection. public static Range Merge(IEnumerable> ranges, Comparison comparison) { return ranges.Aggregate((range1, range2) => range1.Merge(range2, comparison)); } /// /// Merges all consecutive groups of overlapping ranges in a /// collection and returns the resulting collection of ranges. /// /// The collection of ranges. /// The collection of merged ranges. public static IEnumerable> MergeConsecutiveOverlapping(IEnumerable> ranges) { return MergeConsecutiveOverlapping(ranges, Comparer.Default); } /// /// Merges all consecutive groups of overlapping ranges in a /// collection and returns the resulting collection of ranges. /// /// The collection of ranges. /// The comparer used to compare objects of type . /// The collection of merged ranges. public static IEnumerable> MergeConsecutiveOverlapping(IEnumerable> ranges, IComparer comparer) { return MergeConsecutiveOverlapping(ranges, comparer.Compare); } /// /// Merges all consecutive groups of overlapping ranges in a /// collection and returns the resulting collection of ranges. /// /// The collection of ranges. /// The comparison used to compare objects of type . /// The collection of merged ranges. public static IEnumerable> MergeConsecutiveOverlapping(IEnumerable> ranges, Comparison comparison) { Range currentRange = null; foreach (Range range in ranges) { if ((object)currentRange == null) { currentRange = range; } else if (currentRange.Overlaps(range, comparison)) { currentRange = currentRange.Merge(range, comparison); } else { yield return currentRange; currentRange = range; } } if ((object)currentRange != null) yield return currentRange; } /// /// Merges all consecutive groups of overlapping ranges in a /// collection and returns the resulting collection of ranges. /// /// The collection of ranges. /// The collection of merged ranges. /// This method does not preserve the order of the source collection. public static IEnumerable> MergeAllOverlapping(IEnumerable> ranges) { return MergeAllOverlapping(ranges, Comparer.Default); } /// /// Merges all consecutive groups of overlapping ranges in a /// collection and returns the resulting collection of ranges. /// /// The collection of ranges. /// The comparison used to compare objects of type . /// The collection of merged ranges. /// This method does not preserve the order of the source collection. public static IEnumerable> MergeAllOverlapping(IEnumerable> ranges, Comparison comparison) { return MergeAllOverlapping(ranges, Comparer.Create(comparison)); } /// /// Merges all consecutive groups of overlapping ranges in a /// collection and returns the resulting collection of ranges. /// /// The collection of ranges. /// The comparer used to compare objects of type . /// The collection of merged ranges. /// This method does not preserve the order of the source collection. public static IEnumerable> MergeAllOverlapping(IEnumerable> ranges, IComparer comparer) { return MergeConsecutiveOverlapping(ranges.OrderBy(range => range.Start, comparer)); } #endregion } }