< Summary

Information
Class: MyNet.Primitives.Intervals.Interval<T1, T2>
Assembly: MyNet.Primitives
File(s): https://raw.githubusercontent.com/sandre58/MyNet/85372080fe102cd9ee155ceab49ae000e7f66103/src/MyNet.Primitives/Intervals/Interval.cs
Tag: 323_28699572109
Line coverage
39%
Covered lines: 73
Uncovered lines: 112
Coverable lines: 185
Total lines: 600
Line coverage: 39.4%
Branch coverage
39%
Covered branches: 77
Total branches: 196
Branch coverage: 39.2%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)78.57%161480%
get_HasStart()100%11100%
get_HasEnd()100%11100%
get_IsUnboundedStart()100%210%
get_IsUnboundedEnd()100%210%
get_IsPoint()0%2040%
MergeOverlapping(...)0%4260%
IsAdjacentTo(...)60%1010100%
Contains(...)100%1212100%
Contains(...)0%620%
Intersects(...)75%272481.81%
CanMerge(...)0%620%
TryMerge(...)0%620%
Intersection(...)50%2280%
Union(...)0%620%
Gap(...)50%6680%
ExpandTo(...)50%8885.71%
ExpandTo(...)100%210%
ContainsStart(...)0%110100%
ContainsEnd(...)0%110100%
op_Equality(...)100%210%
op_Inequality(...)100%210%
op_GreaterThan(...)100%210%
op_LessThan(...)100%210%
op_GreaterThanOrEqual(...)100%210%
op_LessThanOrEqual(...)100%210%
CompareTo(...)57.69%692660%
Equals(...)0%2040%
GetHashCode()100%210%
ToString()0%156120%
MinStart(...)0%110100%
MaxStart(...)40%131069.23%
MinEnd(...)30%131069.23%
MaxEnd(...)0%110100%

File(s)

https://raw.githubusercontent.com/sandre58/MyNet/85372080fe102cd9ee155ceab49ae000e7f66103/src/MyNet.Primitives/Intervals/Interval.cs

#LineLine coverage
 1// -----------------------------------------------------------------------
 2// <copyright file="Interval.cs" company="Stéphane ANDRE">
 3// Copyright (c) Stéphane ANDRE. All rights reserved.
 4// </copyright>
 5// -----------------------------------------------------------------------
 6
 7using System;
 8using System.Collections.Generic;
 9using System.Diagnostics.CodeAnalysis;
 10using System.Linq;
 11
 12namespace MyNet.Primitives.Intervals;
 13
 14/// <summary>
 15/// Represents an interval of values of type T, where T is a struct that implements <see cref="IComparable{T}"/>. This c
 16/// </summary>
 17/// <param name="start">The start boundary of the interval.</param>
 18/// <param name="end">The end boundary of the interval.</param>
 19/// <param name="allowWrappedBounds">Indicates whether wrapped bounds are allowed.</param>
 20/// <exception cref="ArgumentException">Thrown when the start boundary is greater than the end boundary or when the inte
 21public class Interval<T>(IntervalBoundary<T>? start, IntervalBoundary<T>? end, bool allowWrappedBounds = false)
 22    : Interval<T, Interval<T>>(start, end, allowWrappedBounds)
 23    where T : struct, IComparable<T>
 24{
 25    /// <summary>
 26    /// Initializes a new instance of the <see cref="Interval{T}"/> class with the specified start and end values. The c
 27    /// </summary>
 28    /// <param name="start">The start value of the interval.</param>
 29    /// <param name="to">The end value of the interval.</param>
 30    /// <param name="isInclusive">Indicates whether the boundaries are inclusive.</param>
 31    public Interval(T? start, T? to, bool isInclusive = true)
 32        : this(start.HasValue ? new IntervalBoundary<T>(start.Value, isInclusive) : null, to.HasValue ? new IntervalBoun
 33    {
 34    }
 35
 36    /// <inheritdoc/>
 37    protected override Interval<T> Create(IntervalBoundary<T>? start, IntervalBoundary<T>? end) => new(start, end);
 38}
 39
 40/// <summary>
 41/// Represents an interval of values of type T, where T is a struct that implements <see cref="IComparable{T}"/>.
 42/// </summary>
 43/// <typeparam name="T">The type of the values in the interval.</typeparam>
 44/// <typeparam name="TSelf">The type of the interval.</typeparam>
 45public abstract class Interval<T, TSelf> : IInterval<T>
 46    where T : struct, IComparable<T>
 47    where TSelf : Interval<T, TSelf>
 48{
 49    /// <summary>
 50    /// Initializes a new instance of the <see cref="Interval{T, TSelf}"/> class with the specified start and end bounda
 51    /// </summary>
 52    /// <param name="start">The start boundary of the interval.</param>
 53    /// <param name="end">The end boundary of the interval.</param>
 54    /// <param name="allowWrappedBounds">Indicates whether wrapped bounds are allowed.</param>
 55    /// <exception cref="ArgumentException">Thrown when the start boundary is greater than the end boundary or when the 
 56    protected Interval(IntervalBoundary<T>? start, IntervalBoundary<T>? end, bool allowWrappedBounds = false)
 57    {
 33058        if (start.HasValue && end.HasValue)
 59        {
 32160            var comparison = start.Value.Value.CompareTo(end.Value.Value);
 61
 32162            switch (comparison)
 63            {
 664                case > 0 when !allowWrappedBounds:
 065                    throw new ArgumentException("Start must be before end.");
 666                case 0 when !start.Value.IsInclusive || !end.Value.IsInclusive:
 067                    throw new ArgumentException("Empty interval.");
 68            }
 69        }
 70
 33071        Start = start;
 33072        End = end;
 33073    }
 74
 75    /// <summary>
 76    /// Gets the start boundary of the interval. The start boundary is represented by an <see cref="IntervalBoundary{T}"
 77    /// </summary>
 78    public IntervalBoundary<T>? Start { get; }
 79
 80    /// <summary>
 81    /// Gets the end boundary of the interval. The end boundary is represented by an <see cref="IntervalBoundary{T}"/> s
 82    /// </summary>
 83    public IntervalBoundary<T>? End { get; }
 84
 85    /// <summary>
 86    /// Gets a value indicating whether the interval has a start boundary. An interval is considered to have a start bou
 87    /// </summary>
 29788    public bool HasStart => Start.HasValue;
 89
 90    /// <summary>
 91    /// Gets a value indicating whether the interval has an end boundary. An interval is considered to have an end bound
 92    /// </summary>
 25893    public bool HasEnd => End.HasValue;
 94
 95    /// <summary>
 96    /// Gets a value indicating whether the interval is unbounded on the lower end. An interval is considered unbounded 
 97    /// </summary>
 098    public bool IsUnboundedStart => !HasStart;
 99
 100    /// <summary>
 101    /// Gets a value indicating whether the interval is unbounded on the upper end. An interval is considered unbounded 
 102    /// </summary>
 0103    public bool IsUnboundedEnd => !HasEnd;
 104
 105    /// <summary>
 106    /// Gets a value indicating whether the interval represents a single point. An interval is considered a point if it 
 107    /// </summary>
 0108    public bool IsPoint => HasStart && HasEnd && Start!.Value.Value.CompareTo(End!.Value.Value) == 0;
 109
 110    /// <summary>
 111    /// Merges a collection of intervals by combining any overlapping or adjacent intervals into a single interval. The 
 112    /// </summary>
 113    /// <param name="intervals">The collection of intervals to merge.</param>
 114    /// <returns>A collection of merged intervals.</returns>
 115    public static IReadOnlyCollection<TSelf> MergeOverlapping(IEnumerable<TSelf> intervals)
 116    {
 0117        var ordered = intervals.Order().ToList();
 118
 0119        if (ordered.Count == 0)
 0120            return [];
 121
 0122        var result = new List<TSelf>();
 123
 0124        var current = ordered[0];
 125
 0126        for (var i = 1; i < ordered.Count; i++)
 127        {
 0128            var next = ordered[i];
 129
 0130            if (current.TryMerge(next, out var merged))
 131            {
 0132                current = merged;
 0133                continue;
 134            }
 135
 0136            result.Add(current);
 0137            current = next;
 138        }
 139
 0140        result.Add(current);
 141
 0142        return result;
 143    }
 144
 145    /// <summary>
 146    /// Determines whether the current interval is adjacent to another interval. Two intervals are considered adjacent i
 147    /// </summary>
 148    /// <param name="right">The interval to check for adjacency.</param>
 149    /// <returns><c>true</c> if the intervals are adjacent; otherwise, <c>false</c>.</returns>
 6150    public bool IsAdjacentTo(TSelf right) => End?.Value.CompareNullableTo(right.Start?.Value) == 0 || right.End?.Value.C
 151
 152    /// <summary>
 153    /// Creates a new instance of the interval with the specified start and end boundaries. This method is abstract and 
 154    /// </summary>
 155    /// <param name="start">The start boundary of the interval.</param>
 156    /// <param name="end">The end boundary of the interval.</param>
 157    /// <returns>A new instance of the interval with the specified boundaries.</returns>
 158    protected abstract TSelf Create(IntervalBoundary<T>? start, IntervalBoundary<T>? end);
 159
 160    /// <summary>
 161    /// Determines whether the interval contains a specified value.
 162    /// </summary>
 163    /// <param name="value">The value to check.</param>
 164    /// <returns><c>true</c> if the interval contains the specified value; otherwise, <c>false</c>.</returns>
 165    public virtual bool Contains(T value)
 166    {
 120167        var afterStart =
 120168            !HasStart ||
 120169            value.CompareTo(Start!.Value.Value) > 0 ||
 120170            (value.CompareTo(Start.Value.Value) == 0 && Start.Value.IsInclusive);
 171
 120172        var beforeEnd =
 120173            !HasEnd ||
 120174            value.CompareTo(End!.Value.Value) < 0 ||
 120175            (value.CompareTo(End.Value.Value) == 0 && End.Value.IsInclusive);
 176
 120177        return afterStart && beforeEnd;
 178    }
 179
 180    /// <summary>
 181    /// Determines whether the current interval contains another interval. An interval A is considered to contain anothe
 182    /// </summary>
 183    /// <param name="other">The interval to check for containment.</param>
 184    /// <returns><c>true</c> if the current interval contains the specified interval; otherwise, <c>false</c>.</returns>
 0185    public virtual bool Contains(IInterval<T> other) => ContainsStart(other) && ContainsEnd(other);
 186
 187    /// <summary>
 188    /// Determines whether the current interval intersects with another interval. Two intervals are considered to inters
 189    /// </summary>
 190    /// <param name="other">The interval to check for intersection.</param>
 191    /// <returns><c>true</c> if the current interval intersects with the specified interval; otherwise, <c>false</c>.</r
 192    public virtual bool Intersects(IInterval<T> other)
 193    {
 24194        if (End.HasValue && other.Start.HasValue)
 195        {
 24196            var comparison = End.Value.Value.CompareTo(other.Start.Value.Value);
 197
 24198            switch (comparison)
 199            {
 200                case < 0:
 3201                case 0 when !End.Value.IsInclusive || !other.Start.Value.IsInclusive:
 15202                    return false;
 203            }
 204        }
 205
 9206        if (other.End.HasValue && Start.HasValue)
 207        {
 9208            var comparison = other.End.Value.Value.CompareTo(Start.Value.Value);
 209
 9210            switch (comparison)
 211            {
 212                case < 0:
 0213                case 0 when !other.End.Value.IsInclusive || !Start.Value.IsInclusive:
 0214                    return false;
 215            }
 216        }
 217
 9218        return true;
 219    }
 220
 221    /// <summary>
 222    /// Determines whether the current interval can be merged with the specified interval. Two intervals can be merged i
 223    /// </summary>
 224    /// <param name="right">The interval to compare with the current interval.</param>
 225    /// <returns><c>true</c> if the current interval can be merged with the specified interval; otherwise, <c>false</c>.
 0226    public bool CanMerge(TSelf right) => Intersects(right) || this.Touches(right);
 227
 228    /// <summary>
 229    /// Attempts to merge the current interval with the specified interval. If the intervals can be merged (i.e., they o
 230    /// </summary>
 231    /// <param name="right">The interval to merge with the current interval.</param>
 232    /// <param name="merged">When this method returns, contains the merged interval if the merge was successful; otherwi
 233    /// <returns><c>true</c> if the intervals were successfully merged; otherwise, <c>false</c>.</returns>
 234    public bool TryMerge(TSelf right, [NotNullWhen(true)] out TSelf? merged)
 235    {
 0236        if (!CanMerge(right))
 237        {
 0238            merged = null;
 0239            return false;
 240        }
 241
 0242        var start = MinStart((TSelf)this, right);
 0243        var end = MaxEnd((TSelf)this, right);
 244
 0245        merged = Create(start, end);
 246
 0247        return true;
 248    }
 249
 250    /// <summary>
 251    /// Calculates the intersection of the current interval with the specified interval. If the intervals intersect, it 
 252    /// </summary>
 253    /// <param name="right">The interval to intersect with the current interval.</param>
 254    /// <returns>The intersection interval if the intervals intersect; otherwise, <c>null</c>.</returns>
 255    public TSelf? Intersection(TSelf right)
 256    {
 6257        if (!Intersects(right))
 0258            return null;
 259
 6260        var start = MaxStart((TSelf)this, right);
 6261        var end = MinEnd((TSelf)this, right);
 262
 6263        return Create(start, end);
 264    }
 265
 266    /// <summary>
 267    /// Calculates the union of the current interval with the specified interval. If the intervals can be merged (i.e., 
 268    /// </summary>
 269    /// <param name="right">The interval to intersect with the current interval.</param>
 270    /// <returns>The union interval if the intervals union; otherwise, <c>null</c>.</returns>
 271    public IReadOnlyCollection<TSelf> Union(TSelf right)
 0272        => TryMerge(right, out var merged) ? [merged] : new List<TSelf> { (TSelf)this, right }.Order().ToArray();
 273
 274    /// <summary>
 275    /// Calculates the gap between the current interval and the specified interval. If the intervals do not intersect or
 276    /// </summary>
 277    /// <param name="right">The interval to intersect with the current interval.</param>
 278    /// <returns>The gap interval if the intervals do not intersect or touch; otherwise, <c>null</c>.</returns>
 279    public TSelf? Gap(TSelf right)
 280    {
 12281        if (Intersects(right) || this.Touches(right))
 0282            return null;
 283
 12284        var ordered = CompareTo(right) <= 0 ? ((TSelf)this, right) : (right, (TSelf)this);
 285
 12286        return Create(new IntervalBoundary<T>(ordered.Item1.End!.Value.Value, !ordered.Item1.End.Value.IsInclusive),
 12287            new IntervalBoundary<T>(ordered.Item2.Start!.Value.Value, !ordered.Item2.Start.Value.IsInclusive));
 288    }
 289
 290    /// <summary>
 291    /// Expands the current interval to include the specified value. If the value is outside the current interval, it cr
 292    /// </summary>
 293    /// <param name="value">The value to include in the interval.</param>
 294    /// <param name="inclusive">Specifies whether the new boundaries should be inclusive or exclusive.</param>
 295    /// <returns>A new interval that includes the specified value.</returns>
 296    public TSelf ExpandTo(T value, bool inclusive = true)
 297    {
 12298        var start = Start;
 12299        var end = End;
 300
 12301        if (!HasStart || value.CompareTo(Start!.Value.Value) < 0)
 302        {
 12303            start = new IntervalBoundary<T>(value, inclusive);
 304        }
 305
 12306        if (!HasEnd || value.CompareTo(End!.Value.Value) > 0)
 307        {
 0308            end = new IntervalBoundary<T>(value, inclusive);
 309        }
 310
 12311        return Create(start, end);
 312    }
 313
 314    /// <summary>
 315    /// Expands the current interval to include another interval. If the other interval is outside the current interval,
 316    /// </summary>
 317    /// <param name="other">The interval to include in the current interval.</param>
 318    /// <returns>A new interval that includes the specified interval.</returns>
 0319    public IInterval<T> ExpandTo(TSelf other) => Create(MinStart((TSelf)this, other), MaxEnd((TSelf)this, other));
 320
 321    /// <summary>
 322    /// Determines whether the current interval contains another interval. An interval A is considered to contain anothe
 323    /// </summary>
 324    /// <param name="other">The interval to check for containment.</param>
 325    /// <returns><c>true</c> if the current interval contains the specified interval; otherwise, <c>false</c>.</returns>
 326    private bool ContainsStart(IInterval<T> other)
 327    {
 0328        if (!HasStart)
 0329            return true;
 330
 0331        if (!other.HasStart)
 0332            return false;
 333
 0334        var comparison =
 0335            Start!.Value.Value.CompareTo(other.Start!.Value.Value);
 336
 0337        return comparison switch
 0338        {
 0339            < 0 => true,
 0340            > 0 => false,
 0341            _ => Start.Value.IsInclusive || !other.Start.Value.IsInclusive
 0342        };
 343    }
 344
 345    /// <summary>
 346    /// Determines whether the current interval contains another interval. An interval A is considered to contain anothe
 347    /// </summary>
 348    /// <param name="other">The interval to check for containment.</param>
 349    /// <returns><c>true</c> if the current interval contains the specified interval; otherwise, <c>false</c>.</returns>
 350    private bool ContainsEnd(IInterval<T> other)
 351    {
 0352        if (!HasEnd)
 0353            return true;
 354
 0355        if (!other.HasEnd)
 0356            return false;
 357
 0358        var comparison =
 0359            End!.Value.Value.CompareTo(other.End!.Value.Value);
 360
 0361        return comparison switch
 0362        {
 0363            > 0 => true,
 0364            < 0 => false,
 0365            _ => End.Value.IsInclusive || !other.End.Value.IsInclusive
 0366        };
 367    }
 368
 369    /// <summary>
 370    /// Determines whether two intervals are equal by comparing their boundaries. Two intervals are considered equal if 
 371    /// </summary>
 372    /// <param name="left">The left interval to compare.</param>
 373    /// <param name="right">The right interval to compare.</param>
 374    /// <returns><c>true</c> if the left interval is equal to the right interval; otherwise, <c>false</c>.</returns>
 0375    public static bool operator ==(Interval<T, TSelf> left, IInterval<T> right) => left.Equals(right);
 376
 377    /// <summary>
 378    /// Determines whether two intervals are not equal by comparing their boundaries. Two intervals are considered not e
 379    /// </summary>
 380    /// <param name="left">The left interval to compare.</param>
 381    /// <param name="right">The right interval to compare.</param>
 382    /// <returns><c>true</c> if the left interval is not equal to the right interval; otherwise, <c>false</c>.</returns>
 0383    public static bool operator !=(Interval<T, TSelf> left, IInterval<T> right) => !left.Equals(right);
 384
 385    /// <summary>
 386    /// Determines whether the current interval is greater than another interval. An interval A is considered to be grea
 387    /// </summary>
 388    /// <param name="left">The left interval to compare.</param>
 389    /// <param name="right">The right interval to compare.</param>
 390    /// <returns><c>true</c> if the left interval is greater than the right interval; otherwise, <c>false</c>.</returns>
 0391    public static bool operator >(Interval<T, TSelf> left, IInterval<T> right) => left.CompareTo(right) > 0;
 392
 393    /// <summary>
 394    /// Determines whether the current interval is less than another interval. An interval A is considered to be less th
 395    /// </summary>
 396    /// <param name="left">The left interval to compare.</param>
 397    /// <param name="right">The right interval to compare.</param>
 398    /// <returns><c>true</c> if the left interval is less than the right interval; otherwise, <c>false</c>.</returns>
 0399    public static bool operator <(Interval<T, TSelf> left, IInterval<T> right) => left.CompareTo(right) < 0;
 400
 401    /// <summary>
 402    /// Determines whether the current interval is greater than or equal to another interval. An interval A is considere
 403    /// </summary>
 404    /// <param name="left">The left interval to compare.</param>
 405    /// <param name="right">The right interval to compare.</param>
 406    /// <returns><c>true</c> if the left interval is greater than or equal to the right interval; otherwise, <c>false</c
 0407    public static bool operator >=(Interval<T, TSelf> left, IInterval<T> right) => left.CompareTo(right) >= 0;
 408
 409    /// <summary>
 410    /// Determines whether the current interval is less than or equal to another interval. An interval A is considered t
 411    /// </summary>
 412    /// <param name="left">The left interval to compare.</param>
 413    /// <param name="right">The right interval to compare.</param>
 414    /// <returns><c>true</c> if the left interval is less than or equal to the right interval; otherwise, <c>false</c>.<
 0415    public static bool operator <=(Interval<T, TSelf> left, IInterval<T> right) => left.CompareTo(right) <= 0;
 416
 417    /// <summary>
 418    /// Compares the current interval with another interval and returns an integer that indicates whether the current in
 419    /// </summary>
 420    /// <param name="other">The interval to compare with the current interval.</param>
 421    /// <returns>An integer that indicates whether the current interval is less than, equal to, or greater than the othe
 422    public int CompareTo(IInterval<T>? other)
 423    {
 30424        if (other is null)
 0425            return 1;
 426
 30427        switch (HasStart)
 428        {
 0429            case false when other.HasStart:
 0430                return -1;
 30431            case true when !other.HasStart:
 0432                return 1;
 433            case true:
 434                {
 30435                    var startComparison = Start!.Value.Value.CompareTo(other.Start!.Value.Value);
 30436                    if (startComparison != 0)
 12437                        return startComparison;
 438
 18439                    if (Start.Value.IsInclusive != other.Start.Value.IsInclusive)
 6440                        return Start.Value.IsInclusive ? -1 : 1;
 441                    break;
 442                }
 443        }
 444
 12445        switch (HasEnd)
 446        {
 0447            case false when other.HasEnd:
 0448                return 1;
 12449            case true when !other.HasEnd:
 0450                return -1;
 451            case false:
 0452                return 0;
 453            default:
 454                {
 12455                    var endComparison = End!.Value.Value.CompareTo(other.End!.Value.Value);
 12456                    return endComparison != 0 ? endComparison : End.Value.IsInclusive == other.End.Value.IsInclusive ? 0
 457                }
 458        }
 459    }
 460
 461    /// <summary>
 462    /// Determines whether the specified object is equal to the current interval. Two intervals are considered equal if 
 463    /// </summary>
 464    /// <param name="obj">The object to compare with the current interval.</param>
 465    /// <returns><c>true</c> if the specified object is equal to the current interval; otherwise, <c>false</c>.</returns
 0466    public override bool Equals(object? obj) => obj is IInterval<T> interval && Start.Equals(interval.Start) && End.Equa
 467
 468    /// <summary>
 469    /// Returns a hash code for the current interval. The hash code is computed based on the Start and End properties of
 470    /// </summary>
 471    /// <returns>A hash code for the current interval.</returns>
 0472    public override int GetHashCode() => HashCode.Combine(Start, End);
 473
 474    /// <summary>
 475    /// Returns a string that represents the current interval. The string is formatted as "Start - End", where Start and
 476    /// </summary>
 477    /// <returns>A string that represents the current interval.</returns>
 478    public override string ToString()
 479    {
 0480        var startBracket = Start?.IsInclusive == true ? "[" : "]";
 0481        var endBracket = End?.IsInclusive == true ? "]" : "[";
 482
 0483        var start = HasStart ? Start!.Value.Value.ToString() : "-∞";
 0484        var end = HasEnd ? End!.Value.Value.ToString() : "+∞";
 485
 0486        return $"{startBracket}{start}; {end}{endBracket}";
 487    }
 488
 489    /// <summary>
 490    /// Determines the minimum start boundary between two intervals. If one of the intervals does not have a defined sta
 491    /// </summary>
 492    /// <param name="left">The first interval to compare.</param>
 493    /// <param name="right">The second interval to compare.</param>
 494    /// <returns>The minimum start boundary between the two intervals.</returns>
 495    private static IntervalBoundary<T>? MinStart(TSelf left, TSelf right)
 496    {
 0497        if (!left.HasStart)
 0498            return left.Start;
 499
 0500        if (!right.HasStart)
 0501            return right.Start;
 502
 0503        var comparison =
 0504            left.Start!.Value.Value.CompareTo(
 0505                right.Start!.Value.Value);
 506
 0507        return comparison switch
 0508        {
 0509            < 0 => left.Start,
 0510            > 0 => right.Start,
 0511            _ => left.Start.Value.IsInclusive ? left.Start : right.Start
 0512        };
 513    }
 514
 515    /// <summary>
 516    /// Determines the maximum start boundary between two intervals. If one of the intervals does not have a defined sta
 517    /// </summary>
 518    /// <param name="left">The first interval to compare.</param>
 519    /// <param name="right">The second interval to compare.</param>
 520    /// <returns>The maximum start boundary between the two intervals.</returns>
 521    private static IntervalBoundary<T>? MaxStart(TSelf left, TSelf right)
 522    {
 6523        if (!left.HasStart)
 0524            return right.Start;
 525
 6526        if (!right.HasStart)
 0527            return left.Start;
 528
 6529        var comparison =
 6530            left.Start!.Value.Value.CompareTo(
 6531                right.Start!.Value.Value);
 532
 6533        return comparison switch
 6534        {
 0535            > 0 => left.Start,
 6536            < 0 => right.Start,
 0537            _ => !left.Start.Value.IsInclusive ? left.Start : right.Start
 6538        };
 539    }
 540
 541    /// <summary>
 542    /// Determines the minimum end boundary between two intervals. If one of the intervals does not have a defined end b
 543    /// </summary>
 544    /// <param name="left">The first interval to compare.</param>
 545    /// <param name="right">The second interval to compare.</param>
 546    /// <returns>The minimum end boundary between the two intervals.</returns>
 547    private static IntervalBoundary<T>? MinEnd(TSelf left, TSelf right)
 548    {
 6549        if (!left.HasEnd)
 0550            return right.End;
 551
 6552        if (!right.HasEnd)
 0553            return left.End;
 554
 6555        var comparison =
 6556            left.End!.Value.Value.CompareTo(
 6557                right.End!.Value.Value);
 558
 6559        return comparison switch
 6560        {
 6561            < 0 => left.End,
 0562            > 0 => right.End,
 0563            _ => !left.End.Value.IsInclusive ? left.End : right.End
 6564        };
 565    }
 566
 567    /// <summary>
 568    /// Determines the maximum end boundary between two intervals. If one of the intervals does not have a defined end b
 569    /// </summary>
 570    /// <param name="left">The first interval to compare.</param>
 571    /// <param name="right">The second interval to compare.</param>
 572    /// <returns>The maximum end boundary between the two intervals.</returns>
 573    private static IntervalBoundary<T>? MaxEnd(TSelf left, TSelf right)
 574    {
 0575        if (!left.HasEnd)
 0576            return left.End;
 577
 0578        if (!right.HasEnd)
 0579            return right.End;
 580
 0581        var comparison = left.End!.Value.Value.CompareTo(right.End!.Value.Value);
 582
 0583        return comparison switch
 0584        {
 0585            > 0 => left.End,
 0586            < 0 => right.End,
 0587            _ => left.End.Value.IsInclusive ? left.End : right.End
 0588        };
 589    }
 590}
 591
 592/// <summary>
 593/// Represents a boundary of an interval, which can be either inclusive or exclusive. An inclusive boundary includes the
 594/// </summary>
 595/// <param name="Value">The value of the boundary.</param>
 596/// <param name="IsInclusive">Indicates whether the boundary is inclusive.</param>
 597/// <typeparam name="T">The type of the value.</typeparam>
 598public readonly record struct IntervalBoundary<T>(T Value, bool IsInclusive = true)
 599    where T : struct, IComparable<T>;
 600

Methods/Properties

.ctor(System.Nullable`1<MyNet.Primitives.Intervals.IntervalBoundary`1<T>>,System.Nullable`1<MyNet.Primitives.Intervals.IntervalBoundary`1<T>>,System.Boolean)
get_HasStart()
get_HasEnd()
get_IsUnboundedStart()
get_IsUnboundedEnd()
get_IsPoint()
MergeOverlapping(System.Collections.Generic.IEnumerable`1<TSelf>)
IsAdjacentTo(TSelf)
Contains(T)
Contains(MyNet.Primitives.Intervals.IInterval`1<T>)
Intersects(MyNet.Primitives.Intervals.IInterval`1<T>)
CanMerge(TSelf)
TryMerge(TSelf,TSelf&)
Intersection(TSelf)
Union(TSelf)
Gap(TSelf)
ExpandTo(T,System.Boolean)
ExpandTo(TSelf)
ContainsStart(MyNet.Primitives.Intervals.IInterval`1<T>)
ContainsEnd(MyNet.Primitives.Intervals.IInterval`1<T>)
op_Equality(MyNet.Primitives.Intervals.Interval`2<T,TSelf>,MyNet.Primitives.Intervals.IInterval`1<T>)
op_Inequality(MyNet.Primitives.Intervals.Interval`2<T,TSelf>,MyNet.Primitives.Intervals.IInterval`1<T>)
op_GreaterThan(MyNet.Primitives.Intervals.Interval`2<T,TSelf>,MyNet.Primitives.Intervals.IInterval`1<T>)
op_LessThan(MyNet.Primitives.Intervals.Interval`2<T,TSelf>,MyNet.Primitives.Intervals.IInterval`1<T>)
op_GreaterThanOrEqual(MyNet.Primitives.Intervals.Interval`2<T,TSelf>,MyNet.Primitives.Intervals.IInterval`1<T>)
op_LessThanOrEqual(MyNet.Primitives.Intervals.Interval`2<T,TSelf>,MyNet.Primitives.Intervals.IInterval`1<T>)
CompareTo(MyNet.Primitives.Intervals.IInterval`1<T>)
Equals(System.Object)
GetHashCode()
ToString()
MinStart(TSelf,TSelf)
MaxStart(TSelf,TSelf)
MinEnd(TSelf,TSelf)
MaxEnd(TSelf,TSelf)