< Summary

Information
Class: MoreStructures.RotatedTextWithTerminator
Assembly: MoreStructures
File(s): /home/runner/work/MoreStructures/MoreStructures/MoreStructures/RotatedTextWithTerminator.cs
Line coverage
100%
Covered lines: 120
Uncovered lines: 0
Coverable lines: 120
Total lines: 158
Line coverage: 100%
Branch coverage
100%
Covered branches: 16
Total branches: 16
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity Line coverage
.ctor(...)100%4100%
get_ValidateInput()100%1100%
get_RotatedText()100%1100%
get_Terminator()100%1100%
get_Item(...)100%1100%
get_Item(...)100%2100%
get_Item(...)100%2100%
get_Length()100%4100%
StartsWith(...)100%2100%
EndsWith(...)100%2100%
GetEnumerator()100%1100%
System.Collections.IEnumerable.GetEnumerator()100%1100%

File(s)

/home/runner/work/MoreStructures/MoreStructures/MoreStructures/RotatedTextWithTerminator.cs

#LineLine coverage
 1using MoreStructures.Utilities;
 2using System.Collections;
 3
 4namespace MoreStructures;
 5
 6/// <summary>
 7/// A text string with a terminator character which has been rotated leftwards or rightwards, of a number of positions
 8/// (0 included).
 9/// </summary>
 10/// <param name="RotatedText">
 11/// The text, defined as an <see cref="IEnumerable{T}"/> of chars and containing the terminator character once, in any
 12/// position of the text.
 13/// </param>
 14/// <param name="Terminator">
 15/// A terminator character, present in the text at most once. If not specified
 16/// <see cref="TextWithTerminator.DefaultTerminator"/> is used.
 17/// </param>
 18/// <param name="ValidateInput">
 19/// Whether the input, and in particular <see cref="RotatedText"/> should be validated, while this object is created.
 20/// Validation takes O(n) time, where n = number of chars in <see cref="RotatedText"/> and can be an heavy operation.
 21/// </param>
 22/// <remarks>
 23///     <para id="usecases">
 24///     USECASES
 25///     <br/>
 26///     - A terminator-terminated rotated text is required by Burrows-Wheeler Transform operations, such as inversion.
 27///       <br/>
 28///     - This object provides type safety, as it allows to tell apart rotated terminator-terminated strings from
 29///       generic ones.
 30///       <br/>
 31///     - Consistently using <see cref="RotatedTextWithTerminator"/>, rather than <see cref="string"/>, in all library
 32///       functionalities ensures that the invariant of a rotated terminator-terminated string is always respected.
 33///       <br/>
 34///     - Most string-related functionalities provided by <see cref="RotatedTextWithTerminator"/>, such as
 35///       <see cref="Length"/> and <see cref="this[Index]"/>, as well as <see cref="IEnumerable{T}"/> and
 36///       <see cref="IEnumerable"/> support, are delegated to the underlying string.
 37///     </para>
 38/// </remarks>
 1186339public record RotatedTextWithTerminator(
 1186340    IEnumerable<char> RotatedText,
 1186341    char Terminator = TextWithTerminator.DefaultTerminator,
 1186742    bool ValidateInput = true)
 1186343    : IValueEnumerable<char>
 1186344{
 1186345    // Lazy initialized
 1186546    private int? _length = null;
 1186347
 1186348    /// <summary>
 1186349    /// <inheritdoc cref="RotatedTextWithTerminator" path="/param[@name='RotatedText']"/>
 1186350    /// </summary>
 1186351    /// <remarks>
 1186352    /// Wrapped into a <see cref="IValueEnumerable{T}"/> to preserve value equality.
 1186353    /// </remarks>
 1186354    /// <value>
 1186355    /// A sequence of chars.
 1186356    /// </value>
 41728457    public IEnumerable<char> RotatedText { get; init; } = RotatedText.AsValue();
 1186358
 1186359    /// <summary>
 1186360    /// <inheritdoc cref="RotatedTextWithTerminator" path="/param[@name='Terminator']"/>
 1186361    /// </summary>
 1186362    /// <value>
 1186363    /// A single char.
 1186364    /// </value>
 1123865    public char Terminator { get; init; } =
 2808466        !ValidateInput || RotatedText.Count(c => c == Terminator) == 1
 1186567        ? Terminator
 1186568        : throw new ArgumentException($"{nameof(Terminator)} should occur in {nameof(RotatedText)} exactly once");
 1186369
 1186370    /// <summary>
 1186371    /// Select a part of <see cref="RotatedText"/> by the provided selector.
 1186372    /// </summary>
 1186373    /// <param name="selector">Any selector acting on a <see cref="RotatedTextWithTerminator"/>.</param>
 1186374    /// <returns>A string containing the selected part.</returns>
 1186375    public string this[TextWithTerminator.ISelector selector] =>
 276        selector.OfRotated(this);
 1186377
 1186378    /// <summary>
 1186379    /// Select a part of <see cref="RotatedText"/> by the provided range (start index included, end index excluded).
 1186380    /// </summary>
 1186381    /// <param name="range">The range applied to the underlying string.</param>
 1186382    /// <returns>A sequence of chars containing the selected part.</returns>
 1186383    public IEnumerable<char> this[Range range] =>
 1184        RotatedText is StringValueEnumerable { StringValue: var str }
 1185        ? str[range]
 1186        : RotatedText.Take(range);
 1186387
 1186388    /// <summary>
 1186389    /// Select a part of <see cref="RotatedText"/> by the provided index (either w.r.t. the start or to the end of the
 1186390    /// text).
 1186391    /// </summary>
 1186392    /// <param name="index">The index applied to the underlying string.</param>
 1186393    /// <returns>A char containing the selected part.</returns>
 1186394    public char this[Index index] =>
 19520595        RotatedText is StringValueEnumerable { StringValue: var str }
 19520596        ? str[index]
 19520597        : RotatedText.ElementAtO1(index);
 1186398
 1186399    /// <summary>
 11863100    /// The total length of <see cref="RotatedText"/>, including the terminator.
 11863101    /// </summary>
 11863102    /// <remarks>
 11863103    ///     <inheritdoc cref="TextWithTerminator.Length" path="/remarks"/>
 11863104    /// </remarks>
 11863105    /// <value>
 11863106    /// A positive integer (at least 1).
 11863107    /// </value>
 11863108    public int Length
 11863109    {
 11863110        get
 612471111        {
 612471112            if (_length == null)
 10718113            {
 10718114                _length =
 10718115                    RotatedText is StringValueEnumerable { StringValue: var str }
 10718116                    ? str.Length
 10718117                    : RotatedText.CountO1();
 10718118            }
 612471119            return _length.Value;
 612471120        }
 11863121    }
 11863122
 11863123    /// <summary>
 11863124    /// Whether this text starts with <paramref name="prefix"/>.
 11863125    /// </summary>
 11863126    /// <param name="prefix">A terminator-included string.</param>
 11863127    /// <returns>True if <see cref="RotatedText"/> starts by <paramref name="prefix"/>.</returns>
 11863128    public bool StartsWith(string prefix) =>
 2129        RotatedText is StringValueEnumerable { StringValue: var str }
 2130        ? str.StartsWith(prefix)
 2131        : RotatedText.Take(prefix.Length).SequenceEqual(prefix);
 11863132
 11863133    /// <summary>
 11863134    /// Whether this text ends with <paramref name="suffix"/>.
 11863135    /// </summary>
 11863136    /// <param name="suffix">A terminator-included string.</param>
 11863137    /// <returns>True if <see cref="RotatedText"/> ends by <paramref name="suffix"/>.</returns>
 11863138    public bool EndsWith(string suffix) =>
 2139        RotatedText is StringValueEnumerable { StringValue: var str }
 2140        ? str.EndsWith(suffix)
 2141        : RotatedText.TakeLast(suffix.Length).SequenceEqual(suffix);
 11863142
 11863143    /// <inheritdoc path="//*[not(self::summary)]"/>
 11863144    /// <summary>
 11863145    /// Returns an enumerator that iterates through the collection of chars of the underlying <see cref="RotatedText"/>
 11863146    /// string, including the <see cref="Terminator"/> char.
 11863147    /// </summary>
 11863148    public IEnumerator<char> GetEnumerator() =>
 6398149        RotatedText.GetEnumerator();
 11863150
 11863151    /// <inheritdoc path="//*[not(self::summary)]"/>
 11863152    /// <summary>
 11863153    /// Returns an enumerator that iterates through the collection of chars of the underlying <see cref="RotatedText"/>
 11863154    /// string, including the <see cref="Terminator"/> char.
 11863155    /// </summary>
 11863156    IEnumerator IEnumerable.GetEnumerator() =>
 1157        ((IEnumerable)RotatedText).GetEnumerator();
 11863158}