File: StringSplit\StringRange.cs
Web Access
Project: src\src\Shared\Shared.csproj (Shared)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
#if !NET8_0_OR_GREATER
 
using System;
using Microsoft.Shared.Diagnostics;
 
#pragma warning disable CA1716
namespace Microsoft.Shared.StringSplit;
#pragma warning restore CA1716
 
#if !SHARED_PROJECT
[System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
#endif
internal readonly struct StringRange : IComparable, IComparable<StringRange>, IEquatable<StringRange>
{
    /// <summary>
    /// Initializes a new instance of the <see cref="StringRange"/> struct.
    /// </summary>
    /// <param name="index">Starting index of the segment.</param>
    /// <param name="count">Number of characters in the segment.</param>
    public StringRange(int index, int count)
    {
        _ = Throw.IfLessThan(index, 0);
        _ = Throw.IfLessThan(count, 0);
 
        Index = index;
        Count = count;
    }
 
    /// <summary>
    /// Gets the starting index of the string.
    /// </summary>
    public int Index { get; }
 
    /// <summary>
    /// Gets the number of characters in the segment.
    /// </summary>
    public int Count { get; }
 
    /// <summary>
    /// Compare current instance of <see cref="StringRange"/> to another.
    /// </summary>
    /// <param name="other">Segment to compare.</param>
    /// <returns>
    /// Returns a value less than zero if this less than other, zero if this equal to other,
    /// or a value greater than zero if this greater than other.
    /// </returns>
    public int CompareTo(StringRange other) => Index.CompareTo(other.Index);
 
    /// <summary>
    /// Compare current instance of <see cref="StringRange"/> to another object.
    /// </summary>
    /// <param name="obj">Segment to compare.</param>
    /// <returns>
    /// Returns a value less than zero if this less than other, zero if this equal to other,
    /// or a value greater than zero if this greater than other.
    /// Null is considered to be less than any instance.
    /// </returns>
    /// <exception cref="ArgumentException">
    /// If object is not of same type.
    /// </exception>
    public int CompareTo(object? obj)
    {
        if (obj is StringRange ss)
        {
            return CompareTo(ss);
        }
 
        if (obj is not null)
        {
            Throw.ArgumentException(nameof(obj), $"Provided value must be of type {typeof(StringRange)}, but was of type {obj.GetType()}.");
        }
 
        return 1;
    }
 
    /// <summary>
    /// Compares two string segments.
    /// </summary>
    /// <param name="other">Segment to compare.</param>
    /// <returns><see langword="true" /> when equal, <see langword="false" /> otherwise.</returns>
    public bool Equals(StringRange other) => other.Index == Index && other.Count == Count;
 
    /// <summary>
    /// Compares two string segments.
    /// </summary>
    /// <param name="obj">Segment to compare.</param>
    /// <returns><see langword="true" /> when equal, <see langword="false" /> otherwise.</returns>
    public override bool Equals(object? obj) => obj is StringRange ss && Equals(ss);
 
    /// <summary>
    /// Returns the hashcode for this instance.
    /// </summary>
    /// <returns>Hash code.</returns>
    public override int GetHashCode() => HashCode.Combine(Index, Count);
 
    /// <summary>
    /// Compares two string segments.
    /// </summary>
    /// <param name="left">Left segment to compare.</param>
    /// <param name="right">Right segment to compare.</param>
    /// <returns><see langword="true" /> when equal, <see langword="false" /> otherwise.</returns>
    public static bool operator ==(StringRange left, StringRange right)
    {
        return left.Equals(right);
    }
 
    /// <summary>
    /// Compares two string segments.
    /// </summary>
    /// <param name="left">Left segment to compare.</param>
    /// <param name="right">Right segment to compare.</param>
    /// <returns><see langword="true" /> when not equal, <see langword="false" /> otherwise.</returns>
    public static bool operator !=(StringRange left, StringRange right)
    {
        return !(left == right);
    }
 
    /// <summary>
    /// Compares two string segments.
    /// </summary>
    /// <param name="left">Left segment to compare.</param>
    /// <param name="right">Right segment to compare.</param>
    /// <returns><see langword="true" /> when first segment is before the second, <see langword="false" /> otherwise.</returns>
    public static bool operator <(StringRange left, StringRange right)
    {
        return left.Index < right.Index;
    }
 
    /// <summary>
    /// Compares two string segments.
    /// </summary>
    /// <param name="left">Left segment to compare.</param>
    /// <param name="right">Right segment to compare.</param>
    /// <returns><see langword="true" /> when first segment is after the second, <see langword="false" /> otherwise.</returns>
    public static bool operator >(StringRange left, StringRange right)
    {
        return left.Index > right.Index;
    }
 
    /// <summary>
    /// Compares two string segments.
    /// </summary>
    /// <param name="left">Left segment to compare.</param>
    /// <param name="right">Right segment to compare.</param>
    /// <returns><see langword="true" /> when first segment is before or at the same index as the second, <see langword="false" /> otherwise.</returns>
    public static bool operator <=(StringRange left, StringRange right)
    {
        return left.Index <= right.Index;
    }
 
    /// <summary>
    /// Compares two string segments.
    /// </summary>
    /// <param name="left">Left segment to compare.</param>
    /// <param name="right">Right segment to compare.</param>
    /// <returns><see langword="true" /> when first segment is at the same index or after the second, <see langword="false" /> otherwise.</returns>
    public static bool operator >=(StringRange left, StringRange right)
    {
        return left.Index >= right.Index;
    }
}
 
#endif