public CompositeRange <T> Intersect <TKey2>(CompositeRange <T, TKey2> other)
        {
            if (IsEmpty)
            {
                return(this);
            }
            if (other.IsEmpty || !ContainingRange.HasIntersection(other.ContainingRange))
            {
                return(Empty);
            }

            var intersectionResult = new List <Range <T> >(SubRanges.Count);

            var rangesToIntersect = new List <Range <T> >(SubRanges);

            foreach (var otherRange in other.GetMergedRanges())
            {
                for (var i = 0; i < rangesToIntersect.Count; i++)
                {
                    var intersectionRange = rangesToIntersect[i];
                    if (intersectionRange.StartsAfter(otherRange))
                    {
                        break;
                    }

                    intersectionRange = intersectionRange.Intersect(otherRange);
                    if (intersectionRange.IsEmpty)
                    {
                        rangesToIntersect.RemoveAt(i);
                        i--;
                    }
                    else
                    {
                        intersectionResult.Add(intersectionRange);
                    }
                }

                if (rangesToIntersect.Count == 0)
                {
                    break;
                }
            }

            CompositeRange <T> result;

            if (intersectionResult.Count == 0)
            {
                result = Empty;
            }
            else
            {
                var overload = IsMerged
                                        ? UnsafeOverload.NoEmptyRangesAlreadySortedAndMerged
                                        : UnsafeOverload.RangesAlreadySorted;

                result = new CompositeRange <T>(intersectionResult, overload);
            }

            return(result);
        }
示例#2
0
        /// <summary>Returns ranges that has intersections with passed range.</summary>
        /// <typeparam name="T">The type of the range values.</typeparam>
        /// <param name="compositeRange">The source range.</param>
        /// <param name="value">The value to check.</param>
        /// <returns>Ranges that has intersections with passed range.</returns>
        public static Range <T>[] GetIntersection <T>(this CompositeRange <T> compositeRange, T value)
        {
            {
                var ranges = new List <Range <T> >();
                if (!compositeRange.ContainingRange.Contains(value))
                {
                    return
                        (#if (!FW452)
                         Array.Empty <Range <T> >());
                }
#else
                         Array <Range <T> > .Empty;
#endif
                foreach (var range in compositeRange.SubRanges)
                {
                    if (range.StartsAfter(value))
                    {
                        break;
                    }
                    if (range.Contains(value))
                    {
                        ranges.Add(range);
                    }
                }
                return(ranges.ToArray());
            }
        }
示例#3
0
        /// <summary>Returns ranges that has intersections with passed range.</summary>
        /// <typeparam name="T">The type of the range values.</typeparam>
        /// <typeparam name="TRange">The type of the range.</typeparam>
        /// <param name="compositeRange">The source range.</param>
        /// <param name="other">The range to check.</param>
        /// <returns>Ranges that has intersections with passed range.</returns>
        private static RangeIntersection <T> GetIntersectionCore <T, TRange>(this CompositeRange <T> compositeRange, TRange other)
            where TRange : IRange <T>
        {
            var ranges = new List <Range <T> >();

            if (!compositeRange.ContainingRange.HasIntersection(other))
            {
                return
                    (GetRangeIntersection(
                         other.From,
                         other.To,
#if (!FW452)
                         Array.Empty <Range <T> >()
#else
                         Array <Range <T> > .Empty
#endif
                         ));
            }
            foreach (var range in compositeRange.SubRanges)
            {
                if (range.From > other.To)
                {
                    break;
                }
                if (range.To >= other.From)
                {
                    ranges.Add(range);
                }
            }
            return(GetRangeIntersection(other.From, other.To, ranges.ToArray()));
        }
        public static void TestCreate()
        {
            var range1 = Range.Create(1, 2);
            var range2 = Range.Create(2, 3);

            var keyedRange1 = Range.Create(1, 2, "A");
            var keyedRange2 = Range.Create(2, 3, "B");

            DoesNotThrow(() => CompositeRange.Create <int>());
            DoesNotThrow(() => CompositeRange.Create(range1));
            DoesNotThrow(() => CompositeRange.Create(range1, range2));
            DoesNotThrow(() => CompositeRange.Create(range1, range1));
            DoesNotThrow(() => CompositeRange.Create(range2, range1));
            Throws <ArgumentNullException>(() => CompositeRange.Create <int>(null));

            DoesNotThrow(() => CompositeRange.Create <int, string>());
            DoesNotThrow(() => CompositeRange.Create(keyedRange1));
            DoesNotThrow(() => CompositeRange.Create(keyedRange1, keyedRange2));
            DoesNotThrow(() => CompositeRange.Create(keyedRange1, keyedRange1));
            DoesNotThrow(() => CompositeRange.Create(keyedRange2, keyedRange1));
            Throws <ArgumentNullException>(() => CompositeRange.Create <int, string>(null));

            AreEqual(new CompositeRange <int>(), CompositeRange <int> .Empty);
            AreEqual(CompositeRange.Create <int>(), CompositeRange <int> .Empty);
            AreEqual(CompositeRange.Create(Range <int> .Empty), CompositeRange <int> .Empty);
            AreEqual(CompositeRange.Create(Range <int> .Empty, Range <int> .Empty), CompositeRange <int> .Empty);
            AreEqual(CompositeRange.Create(Range <int> .Infinite), CompositeRange <int> .Infinite);
        }
示例#5
0
 /// <summary>Creates a new composite range with the key specified.</summary>
 /// <typeparam name="T">The type of the range values.</typeparam>
 /// <typeparam name="T2">The type of new range values.</typeparam>
 /// <param name="compositeRange">The source range.</param>
 /// <param name="fromValueSelector">Callback to obtain a new value for the From boundary. Used if boundary has a value.</param>
 /// <param name="toValueSelector">Callback to obtain a new value for the To boundary. Used if boundary has a value.</param>
 /// <returns>A new composite range with the key specified.</returns>
 public static CompositeRange <T2> WithValues <T, T2>(
     this CompositeRange <T> compositeRange,
     [NotNull, InstantHandle] Func <T, T2> fromValueSelector,
     [NotNull, InstantHandle] Func <T, T2> toValueSelector) =>
 compositeRange.IsEmpty
                                 ? CompositeRange <T2> .Empty
                                 : compositeRange.SubRanges.Select(s => s.WithValues(fromValueSelector, toValueSelector)).ToCompositeRange();
        /// <summary>Indicates whether the current range is equal to another.</summary>
        /// <param name="other">A range to compare with this.</param>
        /// <returns>
        /// <c>True</c> if the current range is equal to the <paramref name="other"/> parameter;
        /// otherwise, false.
        /// </returns>
        public bool Equals(CompositeRange <T> other)
        {
            if (IsEmpty)
            {
                return(other.IsEmpty);
            }
            if (other.IsEmpty)
            {
                return(false);
            }

            DebugCode.BugIf(_ranges == null, "_ranges == null");
            DebugCode.BugIf(other._ranges == null, "other._ranges == null");

            var otherRanges = other._ranges;

            if (_containingRange != other._containingRange || _ranges.Count != otherRanges.Count)
            {
                return(false);
            }

            for (var i = 0; i < _ranges.Count; i++)
            {
                if (!_ranges[i].Equals(otherRanges[i]))
                {
                    return(false);
                }
            }

            return(true);
        }
        public bool HasIntersection <TKey2>(CompositeRange <T, TKey2> other)
        {
            if (IsEmpty && other.IsEmpty)
            {
                return(true);
            }
            if (!ContainingRange.HasIntersection(other.ContainingRange))
            {
                return(false);
            }

            var result = false;

            using (var containingRanges = GetMergedRanges().GetEnumerator())
            {
                var hasContainingRange = containingRanges.MoveNext();
                foreach (var otherRange in other.GetMergedRanges())
                {
                    while (hasContainingRange && containingRanges.Current.EndsBefore(otherRange))
                    {
                        hasContainingRange = containingRanges.MoveNext();
                    }

                    if (!hasContainingRange || containingRanges.Current.HasIntersection(otherRange))
                    {
                        result = hasContainingRange;
                        break;
                    }
                }
            }

            return(result);
        }
示例#8
0
        /// <summary>Determines whether the composite range has intersection with another range.</summary>
        /// <typeparam name="T">The type of the range values.</typeparam>
        /// <typeparam name="TCompositeRange">The type of another range.</typeparam>
        /// <param name="compositeRange">The source range.</param>
        /// <param name="other">The range to check.</param>
        /// <returns><c>true</c>, if the composite range has intersection with another range.</returns>
        public static bool HasIntersection <T, TCompositeRange>(
            this CompositeRange <T> compositeRange, TCompositeRange other)
            where TCompositeRange : ICompositeRange <T>
        {
            if (compositeRange.IsEmpty && other.IsEmpty)
            {
                return(true);
            }
            if (!compositeRange.ContainingRange.HasIntersection(other.ContainingRange))
            {
                return(false);
            }

            bool result = false;

            using (var containingRanges = compositeRange.GetMergedRanges().GetEnumerator())
            {
                bool hasContainingRange = containingRanges.MoveNext();
                foreach (var otherRange in other.GetMergedRanges())
                {
                    while (hasContainingRange && containingRanges.Current.EndsBefore(otherRange))
                    {
                        hasContainingRange = containingRanges.MoveNext();
                    }

                    if (!hasContainingRange || containingRanges.Current.HasIntersection(otherRange))
                    {
                        result = hasContainingRange;
                        break;
                    }
                }
            }

            return(result);
        }
示例#9
0
        /// <summary>Indicates whether the current range is equal to another.</summary>
        /// <param name="other">A range to compare with this.</param>
        /// <returns>
        /// <c>True</c> if the current range is equal to the <paramref name="other"/> parameter;
        /// otherwise, false.
        /// </returns>
        public bool Equals(CompositeRange <T, TKey> other)
        {
            // TODO: BADCODE, rewrite

            if (IsEmpty)
            {
                return(other.IsEmpty);
            }
            if (other.IsEmpty)
            {
                return(false);
            }

            DebugCode.BugIf(_ranges == null, "_ranges == null");
            DebugCode.BugIf(other._ranges == null, "other._ranges == null");

            var otherRanges = other._ranges;

            if (_containingRange != other._containingRange || _ranges.Count != otherRanges.Count)
            {
                return(false);
            }

            var previousRange = Range <T> .Empty;
            IDictionary <(TKey, int), int> keys = new Dictionary <(TKey, int), int>();

            var nullKeysCount = 0;

            for (var i = 0; i < _ranges.Count; i++)
            {
                var currentWithoutKey = _ranges[i].WithoutKey();

                // TODO: helper method to compare without key.
                if (!currentWithoutKey.Equals(otherRanges[i].WithoutKey()))
                {
                    return(false);
                }

                if (currentWithoutKey != previousRange)
                {
                    var sameKeys = nullKeysCount == 0 && keys.Values.All(a => a == 0);
                    if (!sameKeys)
                    {
                        return(false);
                    }

                    keys.Clear();
                    nullKeysCount = 0;
                }

                var key = _ranges[i].Key;
                if (key == null)
                {
                    nullKeysCount++;
                }
                else
                {
                    keys[(key, 0)] = keys.GetValueOrDefault((key, 0)) + 1;
        public static CompositeRange <T, TKey> Intersect <T, TKey>(
            this CompositeRange <T, TKey> compositeRange,

            #region T4-dont-replace
            Range <T> other
            #endregion

            ) =>
        Intersect(compositeRange, other.ToCompositeRange());
        public CompositeRange <T> Except <TKey2>(CompositeRange <T, TKey2> other)
        {
            if (IsEmpty || other.IsEmpty || !ContainingRange.HasIntersection(other.ContainingRange))
            {
                return(this);
            }

            return(Intersect(other.GetComplementation()));
        }
示例#12
0
        /// <summary>Returns ranges that has intersections with passed range.</summary>
        /// <typeparam name="T">The type of the range values.</typeparam>
        /// <param name="compositeRange">The source range.</param>
        /// <param name="other">The range to check.</param>
        /// <returns>Ranges that has intersections with passed range.</returns>
        public static RangeIntersection <T> GetIntersection <T>(
            this CompositeRange <T> compositeRange,

            #region T4-dont-replace
            Range <T> other
            #endregion

            ) =>
        GetIntersectionCore(compositeRange, other);
示例#13
0
        /// <summary>Returns source range with other range excluded.</summary>
        /// <typeparam name="T">The type of the range values.</typeparam>
        /// <param name="compositeRange">The source range.</param>
        /// <param name="other">The range to intersect with.</param>
        /// <returns>Source range with other range excluded.</returns>
        public static CompositeRange <T> Except <T>(
            this CompositeRange <T> compositeRange,

            #region T4-dont-replace
            Range <T> other
            #endregion

            ) =>
        Except(compositeRange, other.ToCompositeRange());
示例#14
0
        public static IEnumerable <RangeIntersection <T> > GetIntersections <T>(this CompositeRange <T> compositeRange)
        {
            if (compositeRange.IsEmpty)
            {
                yield break;
            }

            var toBoundaries  = new List <RangeBoundaryTo <T> >();         // Sorted by descending.
            var rangesToYield = new List <Range <T> >();

            var fromBoundary = RangeBoundaryFrom <T> .NegativeInfinity;

            foreach (var range in compositeRange.SubRanges)
            {
                // return all ranges that has no intersection with current range.
                while (toBoundaries.Count > 0 && toBoundaries.Last() < range.From)
                {
                    var toBoundary = toBoundaries.Last();
                    yield return(GetRangeIntersection(fromBoundary, toBoundary, rangesToYield));

                    rangesToYield.RemoveAll(r => r.To == toBoundary);
                    toBoundaries.RemoveAt(toBoundaries.Count - 1);
                    fromBoundary = toBoundary.GetComplementation();
                }

                // return rangesToYield as they starts before current range.
                if (fromBoundary < range.From)
                {
                    var to = range.From.GetComplementation();
                    yield return(GetRangeIntersection(fromBoundary, to, rangesToYield));
                }

                // updating the state
                rangesToYield.Add(range);
                InsertInSortedList(
                    toBoundaries, range.To,
                    RangeBoundaryToDescendingComparer <T> .Instance,
                    // ReSharper disable once ArgumentsStyleLiteral
                    skipDuplicates: true);

                fromBoundary = range.From;
            }

            // flush all ranges.
            while (toBoundaries.Count > 0 && toBoundaries.Last() < RangeBoundaryTo <T> .PositiveInfinity)
            {
                var toBoundary = toBoundaries.Last();
                yield return(GetRangeIntersection(fromBoundary, toBoundary, rangesToYield));

                rangesToYield.RemoveAll(r => r.To == toBoundary);
                toBoundaries.RemoveAt(toBoundaries.Count - 1);
                fromBoundary = toBoundary.GetComplementation();
            }

            yield return(GetRangeIntersection(fromBoundary, RangeBoundaryTo <T> .PositiveInfinity, rangesToYield));
        }
示例#15
0
        /// <summary>Determines whether the composite range contains another range.</summary>
        /// <typeparam name="T">The type of the range values.</typeparam>
        /// <param name="compositeRange">The source range.</param>
        /// <param name="other">The range to check.</param>
        /// <returns><c>true</c>, if the composite range contains another range.</returns>
        public static bool Contains <T>(
            this CompositeRange <T> compositeRange,

            #region T4-dont-replace
            Range <T> other
            #endregion

            ) =>
        compositeRange.ContainingRange.Contains(other) &&
        compositeRange.GetMergedRanges().Any(r => r.Contains(other));
示例#16
0
        /// <summary>Determines whether the composite range has intersection with another range.</summary>
        /// <typeparam name="T">The type of the range values.</typeparam>
        /// <param name="compositeRange">The source range.</param>
        /// <param name="other">The range to check.</param>
        /// <returns><c>true</c>, if the composite range has intersection with another range.</returns>
        public static bool HasIntersection <T>(
            this CompositeRange <T> compositeRange,

            #region T4-dont-replace
            Range <T> other
            #endregion

            ) =>
        compositeRange.ContainingRange.HasIntersection(other) &&
        compositeRange.SubRanges.Any(r => r.HasIntersection(other));
 public IntervalTreeTests()
 {
     _sameStartRanges = Enumerable.Range(0, Count)
                        .ToCompositeRange(i => 0, i => 2 * i, i => i.ToString());
     _sameEndRanges = Enumerable.Range(0, Count)
                      .ToCompositeRange(i => 0, i => 2 * i, i => i.ToString());
     _nonOverlappingRanges = Enumerable.Range(0, Count)
                             .ToCompositeRange(i => 4 * i - 2, i => 4 * i + 2, i => i.ToString());
     _overlappingRanges = Enumerable.Range(0, Count)
                          .ToCompositeRange(i => 4 * i - 2 * (i % 4), i => 4 * i + 2 * (i % 4), i => i.ToString());
 }
示例#18
0
 static IntervalTreeTests()
 {
     _sameStartRanges = Enumerable.Range(0, _count)
                        .ToCompositeRange(i => 0, i => 2 * i, i => i.ToString(CultureInfo.InvariantCulture));
     _sameEndRanges = Enumerable.Range(0, _count)
                      .ToCompositeRange(i => 0, i => 2 * i, i => i.ToString(CultureInfo.InvariantCulture));
     _nonOverlappingRanges = Enumerable.Range(0, _count)
                             .ToCompositeRange(i => 4 * i - 2, i => 4 * i + 2, i => i.ToString(CultureInfo.InvariantCulture));
     _overlappingRanges = Enumerable.Range(0, _count)
                          .ToCompositeRange(i => 4 * i - 2 * (i % 4), i => 4 * i + 2 * (i % 4), i => i.ToString(CultureInfo.InvariantCulture));
 }
示例#19
0
        /// <summary>Returns source range with other range excluded.</summary>
        /// <typeparam name="T">The type of the range values.</typeparam>
        /// <typeparam name="TCompositeRange">The type of another range.</typeparam>
        /// <param name="compositeRange">The source range.</param>
        /// <param name="other">The range to intersect with.</param>
        /// <returns>Source range with other range excluded.</returns>
        public static CompositeRange <T> Except <T, TCompositeRange>(
            this CompositeRange <T> compositeRange, TCompositeRange other)
            where TCompositeRange : ICompositeRange <T>
        {
            if (compositeRange.IsEmpty || other.IsEmpty || !compositeRange.ContainingRange.HasIntersection(other.ContainingRange))
            {
                return(compositeRange);
            }

            return(Intersect(compositeRange, GetComplementationCore <T, TCompositeRange>(other)));
        }
示例#20
0
        /// <summary>
        /// Replaces exclusive boundaries with inclusive ones with the values from the selector callbacks
        /// </summary>
        /// <typeparam name="T">The type of the range values.</typeparam>
        /// <param name="compositeRange">The source range.</param>
        /// <param name="fromValueSelector">Callback to obtain a new value for the From boundary. Used if the boundary is exclusive.</param>
        /// <param name="toValueSelector">Callback to obtain a new value for the To boundary. Used if the boundary is exclusive.</param>
        /// <returns>A range with inclusive boundaries.</returns>
        public static CompositeRange <T> MakeInclusive <T>(
            this CompositeRange <T> compositeRange,
            [NotNull, InstantHandle] Func <T, T> fromValueSelector,
            [NotNull, InstantHandle] Func <T, T> toValueSelector)
        {
            if (compositeRange.IsEmpty)
            {
                return(compositeRange);
            }

            return(compositeRange.SubRanges
                   .Select(r => r.MakeInclusive(fromValueSelector, toValueSelector))
                   .ToCompositeRange());
        }
        public IntervalTreePerfTest()
        {
            _ranges = Enumerable.Range(0, _count)
                      .ToCompositeRange(i => 4 * i - 2 * (i % 4), i => 1 + 4 * i + 2 * (i % 4), i => i.ToString());

            _intersection       = _ranges.SubRanges[1000].WithoutKey();
            _intersectionCostin = new Interval <int>(_intersection.FromValue, _intersection.ToValue);

            _tree       = new IntervalTree <int, string>(_ranges);
            _treeCostin = new IntervalTreeCostin <int, string>(
                _ranges.SubRanges.Select(r => new KeyValuePair <IInterval <int>, string>(
                                             new Interval <int>(r.FromValue, r.ToValue), r.Key))
                );
        }
        public CompositeRange <T> Except(

            #region T4-dont-replace
            CompositeRange <T> other
            #endregion

            )
        {
            if (IsEmpty || other.IsEmpty || !ContainingRange.HasIntersection(other.ContainingRange))
            {
                return(this);
            }

            return(Intersect(other.GetComplementation()));
        }
        public static void TestRangesCore(CompositeRange <int, string> ranges)
        {
            var tree = new IntervalTree <int, string>(ranges);

            for (var i = ranges.ContainingRange.FromValue; i <= ranges.ContainingRange.ToValue; i++)
            {
                var overlapRange = Range.Create(i, i);
                AssertSameOverlap(ranges, tree, overlapRange);
                overlapRange = Range.Create(i - 1, i + 1);
                AssertSameOverlap(ranges, tree, overlapRange);
                overlapRange = Range.Create(i - 2, i + 2);
                AssertSameOverlap(ranges, tree, overlapRange);
                overlapRange = Range.Create(i - 10, i);
                AssertSameOverlap(ranges, tree, overlapRange);
            }
        }
示例#24
0
        /// <summary>Returns a union range containing all subranges.</summary>
        /// <typeparam name="T">The type of the range values.</typeparam>
        /// <param name="compositeRange">The source range.</param>
        /// <param name="other">The range to union with.</param>
        /// <returns>A union range containing all subranges.</returns>
        public static CompositeRange <T> Union <T>(
            this CompositeRange <T> compositeRange, CompositeRange <T> other)
        {
            if (other.IsEmpty)
            {
                return(compositeRange);
            }
            if (compositeRange.IsEmpty)
            {
                return(other);
            }

            var ranges1      = compositeRange.SubRanges;
            var ranges2      = other.SubRanges;
            var resultRanges = new Range <T> [ranges1.Count + ranges2.Count];

            var overload = compositeRange.IsMerged && other.IsMerged
                                ? UnsafeOverload.NoEmptyRangesAlreadySortedAndMerged
                                : UnsafeOverload.RangesAlreadySorted;

            if (other.ContainingRange.EndsBefore(compositeRange.ContainingRange))
            {
                ranges2.CopyTo(resultRanges, 0);
                ranges1.CopyTo(resultRanges, ranges2.Count);
            }
            else
            {
                ranges1.CopyTo(resultRanges, 0);
                ranges2.CopyTo(resultRanges, ranges1.Count);

                if (!compositeRange.ContainingRange.EndsBefore(other.ContainingRange))
                {
                    overload = UnsafeOverload.NoEmptyRanges;
                }
            }
            var result = new CompositeRange <T>(resultRanges, overload);

            if (overload != UnsafeOverload.NoEmptyRangesAlreadySortedAndMerged)
            {
                result = result.Merge();
            }

            return(result);
        }
示例#25
0
        /// <summary>Extends the range from the right.</summary>
        /// <typeparam name="T">The type of the range values.</typeparam>
        /// <param name="compositeRange">The source range.</param>
        /// <param name="to">A new boundary To.</param>
        /// <returns>
        /// A range with a new To boundary or the source fange if the new boundary is less than original.
        /// </returns>
        public static CompositeRange <T> ExtendTo <T>(this CompositeRange <T> compositeRange, RangeBoundaryTo <T> to)
        {
            if (compositeRange.IsEmpty || to.IsEmpty || to <= compositeRange.ContainingRange.To)
            {
                return(compositeRange);
            }

            var ranges = compositeRange.SubRanges.ToArray();

            for (int i = ranges.Length - 1; i >= 0; i--)
            {
                if (ranges[i].To != compositeRange.ContainingRange.To)
                {
                    break;
                }

                ranges[i] = ranges[i].ExtendTo(to);
            }
            return(new CompositeRange <T>(ranges, UnsafeOverload.RangesAlreadySorted));
        }
示例#26
0
        /// <summary>Extends the range from the left.</summary>
        /// <typeparam name="T">The type of the range values.</typeparam>
        /// <param name="compositeRange">The source range.</param>
        /// <param name="from">A new boundary From.</param>
        /// <returns>
        /// A range with a new From boundary or the source fange if the new boundary is greater than original.
        /// </returns>
        public static CompositeRange <T> ExtendFrom <T>(this CompositeRange <T> compositeRange, RangeBoundaryFrom <T> from)
        {
            if (compositeRange.IsEmpty || from.IsEmpty || from >= compositeRange.ContainingRange.From)
            {
                return(compositeRange);
            }

            var ranges = compositeRange.SubRanges.ToArray();

            for (int i = 0; i < ranges.Length; i++)
            {
                if (ranges[i].From != compositeRange.ContainingRange.From)
                {
                    break;
                }

                ranges[i] = ranges[i].ExtendFrom(from);
            }
            return(new CompositeRange <T>(ranges, UnsafeOverload.RangesAlreadySorted));
        }
        private static List <Range <int, string> > IntersectNaive(CompositeRange <int, string> rangeA, Range <int> overlap)
        {
            var result = new List <Range <int, string> >();

            if (!rangeA.ContainingRange.HasIntersection(overlap))
            {
                return(result);
            }
            foreach (var range in rangeA.SubRanges)
            {
                if (range.From > overlap.To)
                {
                    break;
                }
                if (range.To >= overlap.From)
                {
                    result.Add(range);
                }
            }
            return(result);
        }
        public bool Contains(

            #region T4-dont-replace
            CompositeRange <T> other
            #endregion

            )
        {
            if (IsEmpty && other.IsEmpty)
            {
                return(true);
            }
            if (!ContainingRange.Contains(other.ContainingRange))
            {
                return(false);
            }

            var result = true;

            using (var containingRanges = GetMergedRanges().GetEnumerator())
            {
                var hasContainingRange = containingRanges.MoveNext();
                foreach (var otherRange in other.GetMergedRanges())
                {
                    while (hasContainingRange && containingRanges.Current.EndsBefore(otherRange))
                    {
                        hasContainingRange = containingRanges.MoveNext();
                    }

                    if (!hasContainingRange || !containingRanges.Current.Contains(otherRange))
                    {
                        result = false;
                        break;
                    }
                }
            }

            return(result);
        }
        public static void TestCompositeRangeWithKeyProperties()
        {
            var range1A = Range.Create(1, 2, "A");
            var range1B = Range.Create(1, 2, "B");
            var range2C = Range.CreateExclusiveFrom(2, 3, "C");
            var range3A = Range.Create(3, 4).WithKey("A");
            var empty   = Range <int> .Empty.WithKey((string)null);

            var infinite = Range <int> .Infinite.WithKey((string)null);

            var a = new CompositeRange <int, string>();

            AreEqual(a, CompositeRange.Create(empty, empty));
            AreEqual(a, new CompositeRange <int, string>());
            AreEqual(a.SubRanges.Count, 0);
            AreEqual(a.ContainingRange, Range <int> .Empty);
            IsTrue(a.IsEmpty);
            IsFalse(a.IsNotEmpty);
            IsTrue(a.IsMerged);

            a = new CompositeRange <int, string>(infinite);
            AreNotEqual(a, new CompositeRange <int, string>());
            AreEqual(a, CompositeRange.Create(infinite));
            AreNotEqual(a, CompositeRange.Create(infinite, infinite));
            AreEqual(a.SubRanges.Count, 1);
            AreEqual(a.ContainingRange, infinite.WithoutKey());
            AreEqual(a.SubRanges[0], infinite);
            IsFalse(a.IsEmpty);
            IsTrue(a.IsNotEmpty);
            IsTrue(a.IsMerged);

            a = CompositeRange.Create(range1A);
            AreNotEqual(a, new CompositeRange <int, string>());
            AreNotEqual(a, new CompositeRange <int, string>(infinite));
            AreNotEqual(a, CompositeRange.Create(range1A, range1A));
            AreNotEqual(a, CompositeRange.Create(range1B));
            AreEqual(a.SubRanges.Count, 1);
            AreEqual(a.ContainingRange, range1A.WithoutKey());
            AreEqual(a.SubRanges[0], range1A);
            AreNotEqual(a.SubRanges[0], range1B);
            IsFalse(a.IsEmpty);
            IsTrue(a.IsNotEmpty);
            IsTrue(a.IsMerged);

            a = CompositeRange.Create(range1A, range1B);
            AreNotEqual(a, CompositeRange <int> .Empty);
            AreNotEqual(a, CompositeRange <int> .Infinite);
            AreEqual(a, CompositeRange.Create(range1B, range1A));
            AreEqual(a.SubRanges.Count, 2);
            AreEqual(a.ContainingRange, range1A.WithoutKey());
            AreEqual(a.SubRanges[0], range1A);
            AreEqual(a.SubRanges[1], range1B);
            IsFalse(a.IsEmpty);
            IsTrue(a.IsNotEmpty);
            IsFalse(a.IsMerged);

            a = CompositeRange.Create(range1A, range2C);
            AreNotEqual(a, CompositeRange <int> .Empty);
            AreNotEqual(a, CompositeRange <int> .Infinite);
            AreEqual(a, CompositeRange.Create(range2C, range1A));
            AreEqual(a.SubRanges.Count, 2);
            AreEqual(a.ContainingRange, Range.Create(1, 3));
            AreEqual(a.SubRanges[0], range1A);
            AreEqual(a.SubRanges[1], range2C);
            IsFalse(a.IsEmpty);
            IsTrue(a.IsNotEmpty);
            IsFalse(a.IsMerged);
            IsFalse(a.SubRanges[0].HasIntersection(a.SubRanges[1]));
            IsTrue(a.SubRanges[0].To.GetComplementation() == a.SubRanges[1].From);

            a = CompositeRange.Create(range1A, range3A);
            AreNotEqual(a, CompositeRange <int> .Empty);
            AreNotEqual(a, CompositeRange <int> .Infinite);
            AreEqual(a, CompositeRange.Create(range3A, range1A));
            AreEqual(a.SubRanges.Count, 2);
            AreEqual(a.ContainingRange, Range.Create(1, 4));
            AreEqual(a.SubRanges[0], range1A);
            AreEqual(a.SubRanges[1], range3A);
            IsFalse(a.IsEmpty);
            IsTrue(a.IsNotEmpty);
            IsTrue(a.IsMerged);
        }
        public static void TestCompositeRangeRangeProperties()
        {
            var range1   = Range.Create(1, 2);
            var range2   = Range.CreateExclusiveFrom(2, 3);
            var range3   = Range.Create(3, 4);
            var empty    = Range <int> .Empty;
            var infinite = Range <int> .Infinite;

            // ReSharper disable once ObjectCreationAsStatement
            // ReSharper disable once AssignNullToNotNullAttribute
            Throws <ArgumentNullException>(() => new CompositeRange <int>(null));

            var a = new CompositeRange <int>();

            AreEqual(a, CompositeRange <int> .Empty);
            AreEqual(a, CompositeRange.Create(empty, empty));
            AreNotEqual(a, CompositeRange <int> .Infinite);
            AreEqual(a, new CompositeRange <int>());
            AreEqual(a.SubRanges.Count, 0);
            AreEqual(a.ContainingRange, empty);
            IsTrue(a.IsEmpty);
            IsFalse(a.IsNotEmpty);
            IsTrue(a.IsMerged);

            a = new CompositeRange <int>(infinite);
            AreNotEqual(a, CompositeRange <int> .Empty);
            AreEqual(a, CompositeRange <int> .Infinite);
            AreNotEqual(a, CompositeRange.Create(infinite, infinite));
            AreEqual(a.SubRanges.Count, 1);
            AreEqual(a.ContainingRange, infinite);
            AreEqual(a.SubRanges[0], infinite);
            IsFalse(a.IsEmpty);
            IsTrue(a.IsNotEmpty);
            IsTrue(a.IsMerged);

            a = CompositeRange.Create(range1);
            AreNotEqual(a, CompositeRange <int> .Empty);
            AreNotEqual(a, CompositeRange <int> .Infinite);
            AreNotEqual(a, CompositeRange.Create(range1, range1));
            AreEqual(a.SubRanges.Count, 1);
            AreEqual(a.ContainingRange, range1);
            AreEqual(a.SubRanges[0], range1);
            IsFalse(a.IsEmpty);
            IsTrue(a.IsNotEmpty);
            IsTrue(a.IsMerged);

            a = CompositeRange.Create(range1, range1);
            AreNotEqual(a, CompositeRange <int> .Empty);
            AreNotEqual(a, CompositeRange <int> .Infinite);
            AreEqual(a, CompositeRange.Create(range1, range1));
            AreEqual(a.SubRanges.Count, 2);
            AreEqual(a.ContainingRange, range1);
            AreEqual(a.SubRanges[0], range1);
            AreEqual(a.SubRanges[1], range1);
            IsFalse(a.IsEmpty);
            IsTrue(a.IsNotEmpty);
            IsFalse(a.IsMerged);

            a = CompositeRange.Create(range1, range2);
            AreNotEqual(a, CompositeRange <int> .Empty);
            AreNotEqual(a, CompositeRange <int> .Infinite);
            AreEqual(a, CompositeRange.Create(range2, range1));
            AreEqual(a.SubRanges.Count, 2);
            AreEqual(a.ContainingRange, Range.Create(1, 3));
            AreEqual(a.SubRanges[0], range1);
            AreEqual(a.SubRanges[1], range2);
            IsFalse(a.IsEmpty);
            IsTrue(a.IsNotEmpty);
            IsFalse(a.IsMerged);
            IsFalse(a.SubRanges[0].HasIntersection(a.SubRanges[1]));
            IsTrue(a.SubRanges[0].To.GetComplementation() == a.SubRanges[1].From);

            a = CompositeRange.Create(range1, range3);
            AreNotEqual(a, CompositeRange <int> .Empty);
            AreNotEqual(a, CompositeRange <int> .Infinite);
            AreEqual(a, CompositeRange.Create(range3, range1));
            AreEqual(a.SubRanges.Count, 2);
            AreEqual(a.ContainingRange, Range.Create(1, 4));
            AreEqual(a.SubRanges[0], range1);
            AreEqual(a.SubRanges[1], range3);
            IsFalse(a.IsEmpty);
            IsTrue(a.IsNotEmpty);
            IsTrue(a.IsMerged);
        }