| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677 |
- // Licensed to the .NET Foundation under one or more agreements.
- // The .NET Foundation licenses this file to you under the MIT license.
- // See the LICENSE file in the project root for more information.
- using System.Collections.Generic;
- using System.Runtime.CompilerServices;
- using System.Runtime.InteropServices;
- using System.Text;
- using Internal.Runtime.CompilerServices;
- #if BIT64
- using nuint = System.UInt64;
- #else
- using nuint = System.UInt32;
- #endif // BIT64
- namespace System
- {
- /// <summary>
- /// Extension methods for Span{T}, Memory{T}, and friends.
- /// </summary>
- public static partial class MemoryExtensions
- {
- /// <summary>
- /// Removes all leading and trailing white-space characters from the span.
- /// </summary>
- public static ReadOnlySpan<char> Trim(this ReadOnlySpan<char> span)
- {
- int start = 0;
- for (; start < span.Length; start++)
- {
- if (!char.IsWhiteSpace(span[start]))
- break;
- }
- int end = span.Length - 1;
- for (; end >= start; end--)
- {
- if (!char.IsWhiteSpace(span[end]))
- break;
- }
- return span.Slice(start, end - start + 1);
- }
- /// <summary>
- /// Removes all leading white-space characters from the span.
- /// </summary>
- public static ReadOnlySpan<char> TrimStart(this ReadOnlySpan<char> span)
- {
- int start = 0;
- for (; start < span.Length; start++)
- {
- if (!char.IsWhiteSpace(span[start]))
- break;
- }
- return span.Slice(start);
- }
- /// <summary>
- /// Removes all trailing white-space characters from the span.
- /// </summary>
- public static ReadOnlySpan<char> TrimEnd(this ReadOnlySpan<char> span)
- {
- int end = span.Length - 1;
- for (; end >= 0; end--)
- {
- if (!char.IsWhiteSpace(span[end]))
- break;
- }
- return span.Slice(0, end + 1);
- }
- /// <summary>
- /// Removes all leading and trailing occurrences of a specified character.
- /// </summary>
- /// <param name="span">The source span from which the character is removed.</param>
- /// <param name="trimChar">The specified character to look for and remove.</param>
- public static ReadOnlySpan<char> Trim(this ReadOnlySpan<char> span, char trimChar)
- {
- int start = 0;
- for (; start < span.Length; start++)
- {
- if (span[start] != trimChar)
- break;
- }
- int end = span.Length - 1;
- for (; end >= start; end--)
- {
- if (span[end] != trimChar)
- break;
- }
- return span.Slice(start, end - start + 1);
- }
- /// <summary>
- /// Removes all leading occurrences of a specified character.
- /// </summary>
- /// <param name="span">The source span from which the character is removed.</param>
- /// <param name="trimChar">The specified character to look for and remove.</param>
- public static ReadOnlySpan<char> TrimStart(this ReadOnlySpan<char> span, char trimChar)
- {
- int start = 0;
- for (; start < span.Length; start++)
- {
- if (span[start] != trimChar)
- break;
- }
- return span.Slice(start);
- }
- /// <summary>
- /// Removes all trailing occurrences of a specified character.
- /// </summary>
- /// <param name="span">The source span from which the character is removed.</param>
- /// <param name="trimChar">The specified character to look for and remove.</param>
- public static ReadOnlySpan<char> TrimEnd(this ReadOnlySpan<char> span, char trimChar)
- {
- int end = span.Length - 1;
- for (; end >= 0; end--)
- {
- if (span[end] != trimChar)
- break;
- }
- return span.Slice(0, end + 1);
- }
- /// <summary>
- /// Removes all leading and trailing occurrences of a set of characters specified
- /// in a readonly span from the span.
- /// </summary>
- /// <param name="span">The source span from which the characters are removed.</param>
- /// <param name="trimChars">The span which contains the set of characters to remove.</param>
- /// <remarks>If <paramref name="trimChars"/> is empty, white-space characters are removed instead.</remarks>
- public static ReadOnlySpan<char> Trim(this ReadOnlySpan<char> span, ReadOnlySpan<char> trimChars)
- {
- return span.TrimStart(trimChars).TrimEnd(trimChars);
- }
- /// <summary>
- /// Removes all leading occurrences of a set of characters specified
- /// in a readonly span from the span.
- /// </summary>
- /// <param name="span">The source span from which the characters are removed.</param>
- /// <param name="trimChars">The span which contains the set of characters to remove.</param>
- /// <remarks>If <paramref name="trimChars"/> is empty, white-space characters are removed instead.</remarks>
- public static ReadOnlySpan<char> TrimStart(this ReadOnlySpan<char> span, ReadOnlySpan<char> trimChars)
- {
- if (trimChars.IsEmpty)
- {
- return span.TrimStart();
- }
- int start = 0;
- for (; start < span.Length; start++)
- {
- for (int i = 0; i < trimChars.Length; i++)
- {
- if (span[start] == trimChars[i])
- goto Next;
- }
- break;
- Next:
- ;
- }
- return span.Slice(start);
- }
- /// <summary>
- /// Removes all trailing occurrences of a set of characters specified
- /// in a readonly span from the span.
- /// </summary>
- /// <param name="span">The source span from which the characters are removed.</param>
- /// <param name="trimChars">The span which contains the set of characters to remove.</param>
- /// <remarks>If <paramref name="trimChars"/> is empty, white-space characters are removed instead.</remarks>
- public static ReadOnlySpan<char> TrimEnd(this ReadOnlySpan<char> span, ReadOnlySpan<char> trimChars)
- {
- if (trimChars.IsEmpty)
- {
- return span.TrimEnd();
- }
- int end = span.Length - 1;
- for (; end >= 0; end--)
- {
- for (int i = 0; i < trimChars.Length; i++)
- {
- if (span[end] == trimChars[i])
- goto Next;
- }
- break;
- Next:
- ;
- }
- return span.Slice(0, end + 1);
- }
- /// <summary>
- /// Indicates whether the specified span contains only white-space characters.
- /// </summary>
- public static bool IsWhiteSpace(this ReadOnlySpan<char> span)
- {
- for (int i = 0; i < span.Length; i++)
- {
- if (!char.IsWhiteSpace(span[i]))
- return false;
- }
- return true;
- }
- /// <summary>
- /// Searches for the specified value and returns true if found. If not found, returns false. Values are compared using IEquatable{T}.Equals(T).
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <param name="span">The span to search.</param>
- /// <param name="value">The value to search for.</param>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool Contains<T>(this Span<T> span, T value)
- where T : IEquatable<T>
- {
- if (typeof(T) == typeof(byte))
- return SpanHelpers.Contains(
- ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(span)),
- Unsafe.As<T, byte>(ref value),
- span.Length);
- if (typeof(T) == typeof(char))
- return SpanHelpers.Contains(
- ref Unsafe.As<T, char>(ref MemoryMarshal.GetReference(span)),
- Unsafe.As<T, char>(ref value),
- span.Length);
- return SpanHelpers.Contains(ref MemoryMarshal.GetReference(span), value, span.Length);
- }
- /// <summary>
- /// Searches for the specified value and returns true if found. If not found, returns false. Values are compared using IEquatable{T}.Equals(T).
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <param name="span">The span to search.</param>
- /// <param name="value">The value to search for.</param>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool Contains<T>(this ReadOnlySpan<T> span, T value)
- where T : IEquatable<T>
- {
- if (typeof(T) == typeof(byte))
- return SpanHelpers.Contains(
- ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(span)),
- Unsafe.As<T, byte>(ref value),
- span.Length);
- if (typeof(T) == typeof(char))
- return SpanHelpers.Contains(
- ref Unsafe.As<T, char>(ref MemoryMarshal.GetReference(span)),
- Unsafe.As<T, char>(ref value),
- span.Length);
- return SpanHelpers.Contains(ref MemoryMarshal.GetReference(span), value, span.Length);
- }
- /// <summary>
- /// Searches for the specified value and returns the index of its first occurrence. If not found, returns -1. Values are compared using IEquatable{T}.Equals(T).
- /// </summary>
- /// <param name="span">The span to search.</param>
- /// <param name="value">The value to search for.</param>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static int IndexOf<T>(this Span<T> span, T value)
- where T : IEquatable<T>
- {
- if (typeof(T) == typeof(byte))
- return SpanHelpers.IndexOf(
- ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(span)),
- Unsafe.As<T, byte>(ref value),
- span.Length);
- if (typeof(T) == typeof(char))
- return SpanHelpers.IndexOf(
- ref Unsafe.As<T, char>(ref MemoryMarshal.GetReference(span)),
- Unsafe.As<T, char>(ref value),
- span.Length);
- return SpanHelpers.IndexOf(ref MemoryMarshal.GetReference(span), value, span.Length);
- }
- /// <summary>
- /// Searches for the specified sequence and returns the index of its first occurrence. If not found, returns -1. Values are compared using IEquatable{T}.Equals(T).
- /// </summary>
- /// <param name="span">The span to search.</param>
- /// <param name="value">The sequence to search for.</param>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static int IndexOf<T>(this Span<T> span, ReadOnlySpan<T> value)
- where T : IEquatable<T>
- {
- if (typeof(T) == typeof(byte))
- return SpanHelpers.IndexOf(
- ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(span)),
- span.Length,
- ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(value)),
- value.Length);
- if (typeof(T) == typeof(char))
- return SpanHelpers.IndexOf(
- ref Unsafe.As<T, char>(ref MemoryMarshal.GetReference(span)),
- span.Length,
- ref Unsafe.As<T, char>(ref MemoryMarshal.GetReference(value)),
- value.Length);
- return SpanHelpers.IndexOf(ref MemoryMarshal.GetReference(span), span.Length, ref MemoryMarshal.GetReference(value), value.Length);
- }
- /// <summary>
- /// Searches for the specified value and returns the index of its last occurrence. If not found, returns -1. Values are compared using IEquatable{T}.Equals(T).
- /// </summary>
- /// <param name="span">The span to search.</param>
- /// <param name="value">The value to search for.</param>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static int LastIndexOf<T>(this Span<T> span, T value)
- where T : IEquatable<T>
- {
- if (typeof(T) == typeof(byte))
- return SpanHelpers.LastIndexOf(
- ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(span)),
- Unsafe.As<T, byte>(ref value),
- span.Length);
- if (typeof(T) == typeof(char))
- return SpanHelpers.LastIndexOf(
- ref Unsafe.As<T, char>(ref MemoryMarshal.GetReference(span)),
- Unsafe.As<T, char>(ref value),
- span.Length);
- return SpanHelpers.LastIndexOf<T>(ref MemoryMarshal.GetReference(span), value, span.Length);
- }
- /// <summary>
- /// Searches for the specified sequence and returns the index of its last occurrence. If not found, returns -1. Values are compared using IEquatable{T}.Equals(T).
- /// </summary>
- /// <param name="span">The span to search.</param>
- /// <param name="value">The sequence to search for.</param>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static int LastIndexOf<T>(this Span<T> span, ReadOnlySpan<T> value)
- where T : IEquatable<T>
- {
- if (typeof(T) == typeof(byte))
- return SpanHelpers.LastIndexOf(
- ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(span)),
- span.Length,
- ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(value)),
- value.Length);
- return SpanHelpers.LastIndexOf<T>(ref MemoryMarshal.GetReference(span), span.Length, ref MemoryMarshal.GetReference(value), value.Length);
- }
- /// <summary>
- /// Determines whether two sequences are equal by comparing the elements using IEquatable{T}.Equals(T).
- /// </summary>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool SequenceEqual<T>(this Span<T> span, ReadOnlySpan<T> other)
- where T : IEquatable<T>
- {
- int length = span.Length;
- if (default(T) != null && IsTypeComparableAsBytes<T>(out nuint size))
- return length == other.Length &&
- SpanHelpers.SequenceEqual(
- ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(span)),
- ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(other)),
- ((nuint)length) * size); // If this multiplication overflows, the Span we got overflows the entire address range. There's no happy outcome for this api in such a case so we choose not to take the overhead of checking.
- return length == other.Length && SpanHelpers.SequenceEqual(ref MemoryMarshal.GetReference(span), ref MemoryMarshal.GetReference(other), length);
- }
- /// <summary>
- /// Determines the relative order of the sequences being compared by comparing the elements using IComparable{T}.CompareTo(T).
- /// </summary>
- public static int SequenceCompareTo<T>(this Span<T> span, ReadOnlySpan<T> other)
- where T : IComparable<T>
- {
- if (typeof(T) == typeof(byte))
- return SpanHelpers.SequenceCompareTo(
- ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(span)),
- span.Length,
- ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(other)),
- other.Length);
- if (typeof(T) == typeof(char))
- return SpanHelpers.SequenceCompareTo(
- ref Unsafe.As<T, char>(ref MemoryMarshal.GetReference(span)),
- span.Length,
- ref Unsafe.As<T, char>(ref MemoryMarshal.GetReference(other)),
- other.Length);
- return SpanHelpers.SequenceCompareTo(ref MemoryMarshal.GetReference(span), span.Length, ref MemoryMarshal.GetReference(other), other.Length);
- }
- /// <summary>
- /// Searches for the specified value and returns the index of its first occurrence. If not found, returns -1. Values are compared using IEquatable{T}.Equals(T).
- /// </summary>
- /// <param name="span">The span to search.</param>
- /// <param name="value">The value to search for.</param>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static int IndexOf<T>(this ReadOnlySpan<T> span, T value)
- where T : IEquatable<T>
- {
- if (typeof(T) == typeof(byte))
- return SpanHelpers.IndexOf(
- ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(span)),
- Unsafe.As<T, byte>(ref value),
- span.Length);
- if (typeof(T) == typeof(char))
- return SpanHelpers.IndexOf(
- ref Unsafe.As<T, char>(ref MemoryMarshal.GetReference(span)),
- Unsafe.As<T, char>(ref value),
- span.Length);
- return SpanHelpers.IndexOf(ref MemoryMarshal.GetReference(span), value, span.Length);
- }
- /// <summary>
- /// Searches for the specified sequence and returns the index of its first occurrence. If not found, returns -1. Values are compared using IEquatable{T}.Equals(T).
- /// </summary>
- /// <param name="span">The span to search.</param>
- /// <param name="value">The sequence to search for.</param>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static int IndexOf<T>(this ReadOnlySpan<T> span, ReadOnlySpan<T> value)
- where T : IEquatable<T>
- {
- if (typeof(T) == typeof(byte))
- return SpanHelpers.IndexOf(
- ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(span)),
- span.Length,
- ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(value)),
- value.Length);
- if (typeof(T) == typeof(char))
- return SpanHelpers.IndexOf(
- ref Unsafe.As<T, char>(ref MemoryMarshal.GetReference(span)),
- span.Length,
- ref Unsafe.As<T, char>(ref MemoryMarshal.GetReference(value)),
- value.Length);
- return SpanHelpers.IndexOf(ref MemoryMarshal.GetReference(span), span.Length, ref MemoryMarshal.GetReference(value), value.Length);
- }
- /// <summary>
- /// Searches for the specified value and returns the index of its last occurrence. If not found, returns -1. Values are compared using IEquatable{T}.Equals(T).
- /// </summary>
- /// <param name="span">The span to search.</param>
- /// <param name="value">The value to search for.</param>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static int LastIndexOf<T>(this ReadOnlySpan<T> span, T value)
- where T : IEquatable<T>
- {
- if (typeof(T) == typeof(byte))
- return SpanHelpers.LastIndexOf(
- ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(span)),
- Unsafe.As<T, byte>(ref value),
- span.Length);
- if (typeof(T) == typeof(char))
- return SpanHelpers.LastIndexOf(
- ref Unsafe.As<T, char>(ref MemoryMarshal.GetReference(span)),
- Unsafe.As<T, char>(ref value),
- span.Length);
- return SpanHelpers.LastIndexOf<T>(ref MemoryMarshal.GetReference(span), value, span.Length);
- }
- /// <summary>
- /// Searches for the specified sequence and returns the index of its last occurrence. If not found, returns -1. Values are compared using IEquatable{T}.Equals(T).
- /// </summary>
- /// <param name="span">The span to search.</param>
- /// <param name="value">The sequence to search for.</param>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static int LastIndexOf<T>(this ReadOnlySpan<T> span, ReadOnlySpan<T> value)
- where T : IEquatable<T>
- {
- if (typeof(T) == typeof(byte))
- return SpanHelpers.LastIndexOf(
- ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(span)),
- span.Length,
- ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(value)),
- value.Length);
- return SpanHelpers.LastIndexOf<T>(ref MemoryMarshal.GetReference(span), span.Length, ref MemoryMarshal.GetReference(value), value.Length);
- }
- /// <summary>
- /// Searches for the first index of any of the specified values similar to calling IndexOf several times with the logical OR operator. If not found, returns -1.
- /// </summary>
- /// <param name="span">The span to search.</param>
- /// <param name="value0">One of the values to search for.</param>
- /// <param name="value1">One of the values to search for.</param>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static int IndexOfAny<T>(this Span<T> span, T value0, T value1)
- where T : IEquatable<T>
- {
- if (typeof(T) == typeof(byte))
- return SpanHelpers.IndexOfAny(
- ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(span)),
- Unsafe.As<T, byte>(ref value0),
- Unsafe.As<T, byte>(ref value1),
- span.Length);
- if (typeof(T) == typeof(char))
- return SpanHelpers.IndexOfAny(
- ref Unsafe.As<T, char>(ref MemoryMarshal.GetReference(span)),
- Unsafe.As<T, char>(ref value0),
- Unsafe.As<T, char>(ref value1),
- span.Length);
- return SpanHelpers.IndexOfAny(ref MemoryMarshal.GetReference(span), value0, value1, span.Length);
- }
- /// <summary>
- /// Searches for the first index of any of the specified values similar to calling IndexOf several times with the logical OR operator. If not found, returns -1.
- /// </summary>
- /// <param name="span">The span to search.</param>
- /// <param name="value0">One of the values to search for.</param>
- /// <param name="value1">One of the values to search for.</param>
- /// <param name="value2">One of the values to search for.</param>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static int IndexOfAny<T>(this Span<T> span, T value0, T value1, T value2)
- where T : IEquatable<T>
- {
- if (typeof(T) == typeof(byte))
- return SpanHelpers.IndexOfAny(
- ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(span)),
- Unsafe.As<T, byte>(ref value0),
- Unsafe.As<T, byte>(ref value1),
- Unsafe.As<T, byte>(ref value2),
- span.Length);
- if (typeof(T) == typeof(char))
- return SpanHelpers.IndexOfAny(
- ref Unsafe.As<T, char>(ref MemoryMarshal.GetReference(span)),
- Unsafe.As<T, char>(ref value0),
- Unsafe.As<T, char>(ref value1),
- Unsafe.As<T, char>(ref value2),
- span.Length);
- return SpanHelpers.IndexOfAny(ref MemoryMarshal.GetReference(span), value0, value1, value2, span.Length);
- }
- /// <summary>
- /// Searches for the first index of any of the specified values similar to calling IndexOf several times with the logical OR operator. If not found, returns -1.
- /// </summary>
- /// <param name="span">The span to search.</param>
- /// <param name="values">The set of values to search for.</param>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static int IndexOfAny<T>(this Span<T> span, ReadOnlySpan<T> values)
- where T : IEquatable<T>
- {
- if (typeof(T) == typeof(byte))
- {
- ref byte valueRef = ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(values));
- if (values.Length == 2)
- {
- return SpanHelpers.IndexOfAny(
- ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(span)),
- valueRef,
- Unsafe.Add(ref valueRef, 1),
- span.Length);
- }
- else if (values.Length == 3)
- {
- return SpanHelpers.IndexOfAny(
- ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(span)),
- valueRef,
- Unsafe.Add(ref valueRef, 1),
- Unsafe.Add(ref valueRef, 2),
- span.Length);
- }
- else
- {
- return SpanHelpers.IndexOfAny(
- ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(span)),
- span.Length,
- ref valueRef,
- values.Length);
- }
- }
- if (typeof(T) == typeof(char))
- {
- ref var valueRef = ref Unsafe.As<T, char>(ref MemoryMarshal.GetReference(values));
- if (values.Length == 5)
- {
- // Length 5 is a common length for FileSystemName expression (", <, >, *, ?) and in preference to 2 as it has an explicit overload
- return SpanHelpers.IndexOfAny(
- ref Unsafe.As<T, char>(ref MemoryMarshal.GetReference(span)),
- valueRef,
- Unsafe.Add(ref valueRef, 1),
- Unsafe.Add(ref valueRef, 2),
- Unsafe.Add(ref valueRef, 3),
- Unsafe.Add(ref valueRef, 4),
- span.Length);
- }
- else if (values.Length == 2)
- {
- // Length 2 is a common length for simple wildcards (*, ?), directory separators (/, \), quotes (", '), brackets, etc
- return SpanHelpers.IndexOfAny(
- ref Unsafe.As<T, char>(ref MemoryMarshal.GetReference(span)),
- valueRef,
- Unsafe.Add(ref valueRef, 1),
- span.Length);
- }
- else if (values.Length == 4)
- {
- // Length 4 before 3 as 3 has an explicit overload
- return SpanHelpers.IndexOfAny(
- ref Unsafe.As<T, char>(ref MemoryMarshal.GetReference(span)),
- valueRef,
- Unsafe.Add(ref valueRef, 1),
- Unsafe.Add(ref valueRef, 2),
- Unsafe.Add(ref valueRef, 3),
- span.Length);
- }
- else if (values.Length == 3)
- {
- return SpanHelpers.IndexOfAny(
- ref Unsafe.As<T, char>(ref MemoryMarshal.GetReference(span)),
- valueRef,
- Unsafe.Add(ref valueRef, 1),
- Unsafe.Add(ref valueRef, 2),
- span.Length);
- }
- else if (values.Length == 1)
- {
- // Length 1 last, as ctoring a ReadOnlySpan to call this overload for a single value
- // is already throwing away a bunch of performance vs just calling IndexOf
- return SpanHelpers.IndexOf(
- ref Unsafe.As<T, char>(ref MemoryMarshal.GetReference(span)),
- valueRef,
- span.Length);
- }
- }
- return SpanHelpers.IndexOfAny(ref MemoryMarshal.GetReference(span), span.Length, ref MemoryMarshal.GetReference(values), values.Length);
- }
- /// <summary>
- /// Searches for the first index of any of the specified values similar to calling IndexOf several times with the logical OR operator. If not found, returns -1.
- /// </summary>
- /// <param name="span">The span to search.</param>
- /// <param name="value0">One of the values to search for.</param>
- /// <param name="value1">One of the values to search for.</param>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static int IndexOfAny<T>(this ReadOnlySpan<T> span, T value0, T value1)
- where T : IEquatable<T>
- {
- if (typeof(T) == typeof(byte))
- return SpanHelpers.IndexOfAny(
- ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(span)),
- Unsafe.As<T, byte>(ref value0),
- Unsafe.As<T, byte>(ref value1),
- span.Length);
- if (typeof(T) == typeof(char))
- return SpanHelpers.IndexOfAny(
- ref Unsafe.As<T, char>(ref MemoryMarshal.GetReference(span)),
- Unsafe.As<T, char>(ref value0),
- Unsafe.As<T, char>(ref value1),
- span.Length);
- return SpanHelpers.IndexOfAny(ref MemoryMarshal.GetReference(span), value0, value1, span.Length);
- }
- /// <summary>
- /// Searches for the first index of any of the specified values similar to calling IndexOf several times with the logical OR operator. If not found, returns -1.
- /// </summary>
- /// <param name="span">The span to search.</param>
- /// <param name="value0">One of the values to search for.</param>
- /// <param name="value1">One of the values to search for.</param>
- /// <param name="value2">One of the values to search for.</param>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static int IndexOfAny<T>(this ReadOnlySpan<T> span, T value0, T value1, T value2)
- where T : IEquatable<T>
- {
- if (typeof(T) == typeof(byte))
- return SpanHelpers.IndexOfAny(
- ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(span)),
- Unsafe.As<T, byte>(ref value0),
- Unsafe.As<T, byte>(ref value1),
- Unsafe.As<T, byte>(ref value2),
- span.Length);
- if (typeof(T) == typeof(char))
- return SpanHelpers.IndexOfAny(
- ref Unsafe.As<T, char>(ref MemoryMarshal.GetReference(span)),
- Unsafe.As<T, char>(ref value0),
- Unsafe.As<T, char>(ref value1),
- Unsafe.As<T, char>(ref value2),
- span.Length);
- return SpanHelpers.IndexOfAny(ref MemoryMarshal.GetReference(span), value0, value1, value2, span.Length);
- }
- /// <summary>
- /// Searches for the first index of any of the specified values similar to calling IndexOf several times with the logical OR operator. If not found, returns -1.
- /// </summary>
- /// <param name="span">The span to search.</param>
- /// <param name="values">The set of values to search for.</param>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static int IndexOfAny<T>(this ReadOnlySpan<T> span, ReadOnlySpan<T> values)
- where T : IEquatable<T>
- {
- if (typeof(T) == typeof(byte))
- {
- ref byte valueRef = ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(values));
- if (values.Length == 2)
- {
- return SpanHelpers.IndexOfAny(
- ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(span)),
- valueRef,
- Unsafe.Add(ref valueRef, 1),
- span.Length);
- }
- else if (values.Length == 3)
- {
- return SpanHelpers.IndexOfAny(
- ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(span)),
- valueRef,
- Unsafe.Add(ref valueRef, 1),
- Unsafe.Add(ref valueRef, 2),
- span.Length);
- }
- else
- {
- return SpanHelpers.IndexOfAny(
- ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(span)),
- span.Length,
- ref valueRef,
- values.Length);
- }
- }
- if (typeof(T) == typeof(char))
- {
- ref var valueRef = ref Unsafe.As<T, char>(ref MemoryMarshal.GetReference(values));
- if (values.Length == 5)
- {
- // Length 5 is a common length for FileSystemName expression (", <, >, *, ?) and in preference to 2 as it has an explicit overload
- return SpanHelpers.IndexOfAny(
- ref Unsafe.As<T, char>(ref MemoryMarshal.GetReference(span)),
- valueRef,
- Unsafe.Add(ref valueRef, 1),
- Unsafe.Add(ref valueRef, 2),
- Unsafe.Add(ref valueRef, 3),
- Unsafe.Add(ref valueRef, 4),
- span.Length);
- }
- else if (values.Length == 2)
- {
- // Length 2 is a common length for simple wildcards (*, ?), directory separators (/, \), quotes (", '), brackets, etc
- return SpanHelpers.IndexOfAny(
- ref Unsafe.As<T, char>(ref MemoryMarshal.GetReference(span)),
- valueRef,
- Unsafe.Add(ref valueRef, 1),
- span.Length);
- }
- else if (values.Length == 4)
- {
- // Length 4 before 3 as 3 has an explicit overload
- return SpanHelpers.IndexOfAny(
- ref Unsafe.As<T, char>(ref MemoryMarshal.GetReference(span)),
- valueRef,
- Unsafe.Add(ref valueRef, 1),
- Unsafe.Add(ref valueRef, 2),
- Unsafe.Add(ref valueRef, 3),
- span.Length);
- }
- else if (values.Length == 3)
- {
- return SpanHelpers.IndexOfAny(
- ref Unsafe.As<T, char>(ref MemoryMarshal.GetReference(span)),
- valueRef,
- Unsafe.Add(ref valueRef, 1),
- Unsafe.Add(ref valueRef, 2),
- span.Length);
- }
- else if (values.Length == 1)
- {
- // Length 1 last, as ctoring a ReadOnlySpan to call this overload for a single value
- // is already throwing away a bunch of performance vs just calling IndexOf
- return SpanHelpers.IndexOf(
- ref Unsafe.As<T, char>(ref MemoryMarshal.GetReference(span)),
- valueRef,
- span.Length);
- }
- }
- return SpanHelpers.IndexOfAny(ref MemoryMarshal.GetReference(span), span.Length, ref MemoryMarshal.GetReference(values), values.Length);
- }
- /// <summary>
- /// Searches for the last index of any of the specified values similar to calling LastIndexOf several times with the logical OR operator. If not found, returns -1.
- /// </summary>
- /// <param name="span">The span to search.</param>
- /// <param name="value0">One of the values to search for.</param>
- /// <param name="value1">One of the values to search for.</param>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static int LastIndexOfAny<T>(this Span<T> span, T value0, T value1)
- where T : IEquatable<T>
- {
- if (typeof(T) == typeof(byte))
- return SpanHelpers.LastIndexOfAny(
- ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(span)),
- Unsafe.As<T, byte>(ref value0),
- Unsafe.As<T, byte>(ref value1),
- span.Length);
- return SpanHelpers.LastIndexOfAny(ref MemoryMarshal.GetReference(span), value0, value1, span.Length);
- }
- /// <summary>
- /// Searches for the last index of any of the specified values similar to calling LastIndexOf several times with the logical OR operator. If not found, returns -1.
- /// </summary>
- /// <param name="span">The span to search.</param>
- /// <param name="value0">One of the values to search for.</param>
- /// <param name="value1">One of the values to search for.</param>
- /// <param name="value2">One of the values to search for.</param>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static int LastIndexOfAny<T>(this Span<T> span, T value0, T value1, T value2)
- where T : IEquatable<T>
- {
- if (typeof(T) == typeof(byte))
- return SpanHelpers.LastIndexOfAny(
- ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(span)),
- Unsafe.As<T, byte>(ref value0),
- Unsafe.As<T, byte>(ref value1),
- Unsafe.As<T, byte>(ref value2),
- span.Length);
- return SpanHelpers.LastIndexOfAny(ref MemoryMarshal.GetReference(span), value0, value1, value2, span.Length);
- }
- /// <summary>
- /// Searches for the last index of any of the specified values similar to calling LastIndexOf several times with the logical OR operator. If not found, returns -1.
- /// </summary>
- /// <param name="span">The span to search.</param>
- /// <param name="values">The set of values to search for.</param>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static int LastIndexOfAny<T>(this Span<T> span, ReadOnlySpan<T> values)
- where T : IEquatable<T>
- {
- if (typeof(T) == typeof(byte))
- return SpanHelpers.LastIndexOfAny(
- ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(span)),
- span.Length,
- ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(values)),
- values.Length);
- return SpanHelpers.LastIndexOfAny(ref MemoryMarshal.GetReference(span), span.Length, ref MemoryMarshal.GetReference(values), values.Length);
- }
- /// <summary>
- /// Searches for the last index of any of the specified values similar to calling LastIndexOf several times with the logical OR operator. If not found, returns -1.
- /// </summary>
- /// <param name="span">The span to search.</param>
- /// <param name="value0">One of the values to search for.</param>
- /// <param name="value1">One of the values to search for.</param>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static int LastIndexOfAny<T>(this ReadOnlySpan<T> span, T value0, T value1)
- where T : IEquatable<T>
- {
- if (typeof(T) == typeof(byte))
- return SpanHelpers.LastIndexOfAny(
- ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(span)),
- Unsafe.As<T, byte>(ref value0),
- Unsafe.As<T, byte>(ref value1),
- span.Length);
- return SpanHelpers.LastIndexOfAny(ref MemoryMarshal.GetReference(span), value0, value1, span.Length);
- }
- /// <summary>
- /// Searches for the last index of any of the specified values similar to calling LastIndexOf several times with the logical OR operator. If not found, returns -1.
- /// </summary>
- /// <param name="span">The span to search.</param>
- /// <param name="value0">One of the values to search for.</param>
- /// <param name="value1">One of the values to search for.</param>
- /// <param name="value2">One of the values to search for.</param>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static int LastIndexOfAny<T>(this ReadOnlySpan<T> span, T value0, T value1, T value2)
- where T : IEquatable<T>
- {
- if (typeof(T) == typeof(byte))
- return SpanHelpers.LastIndexOfAny(
- ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(span)),
- Unsafe.As<T, byte>(ref value0),
- Unsafe.As<T, byte>(ref value1),
- Unsafe.As<T, byte>(ref value2),
- span.Length);
- return SpanHelpers.LastIndexOfAny(ref MemoryMarshal.GetReference(span), value0, value1, value2, span.Length);
- }
- /// <summary>
- /// Searches for the last index of any of the specified values similar to calling LastIndexOf several times with the logical OR operator. If not found, returns -1.
- /// </summary>
- /// <param name="span">The span to search.</param>
- /// <param name="values">The set of values to search for.</param>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static int LastIndexOfAny<T>(this ReadOnlySpan<T> span, ReadOnlySpan<T> values)
- where T : IEquatable<T>
- {
- if (typeof(T) == typeof(byte))
- return SpanHelpers.LastIndexOfAny(
- ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(span)),
- span.Length,
- ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(values)),
- values.Length);
- return SpanHelpers.LastIndexOfAny<T>(ref MemoryMarshal.GetReference(span), span.Length, ref MemoryMarshal.GetReference(values), values.Length);
- }
- /// <summary>
- /// Determines whether two sequences are equal by comparing the elements using IEquatable{T}.Equals(T).
- /// </summary>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool SequenceEqual<T>(this ReadOnlySpan<T> span, ReadOnlySpan<T> other)
- where T : IEquatable<T>
- {
- int length = span.Length;
- if (default(T) != null && IsTypeComparableAsBytes<T>(out nuint size))
- return length == other.Length &&
- SpanHelpers.SequenceEqual(
- ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(span)),
- ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(other)),
- ((nuint)length) * size); // If this multiplication overflows, the Span we got overflows the entire address range. There's no happy outcome for this api in such a case so we choose not to take the overhead of checking.
- return length == other.Length && SpanHelpers.SequenceEqual(ref MemoryMarshal.GetReference(span), ref MemoryMarshal.GetReference(other), length);
- }
- /// <summary>
- /// Determines the relative order of the sequences being compared by comparing the elements using IComparable{T}.CompareTo(T).
- /// </summary>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static int SequenceCompareTo<T>(this ReadOnlySpan<T> span, ReadOnlySpan<T> other)
- where T : IComparable<T>
- {
- if (typeof(T) == typeof(byte))
- return SpanHelpers.SequenceCompareTo(
- ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(span)),
- span.Length,
- ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(other)),
- other.Length);
- if (typeof(T) == typeof(char))
- return SpanHelpers.SequenceCompareTo(
- ref Unsafe.As<T, char>(ref MemoryMarshal.GetReference(span)),
- span.Length,
- ref Unsafe.As<T, char>(ref MemoryMarshal.GetReference(other)),
- other.Length);
- return SpanHelpers.SequenceCompareTo(ref MemoryMarshal.GetReference(span), span.Length, ref MemoryMarshal.GetReference(other), other.Length);
- }
- /// <summary>
- /// Determines whether the specified sequence appears at the start of the span.
- /// </summary>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool StartsWith<T>(this Span<T> span, ReadOnlySpan<T> value)
- where T : IEquatable<T>
- {
- int valueLength = value.Length;
- if (default(T) != null && IsTypeComparableAsBytes<T>(out nuint size))
- return valueLength <= span.Length &&
- SpanHelpers.SequenceEqual(
- ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(span)),
- ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(value)),
- ((nuint)valueLength) * size); // If this multiplication overflows, the Span we got overflows the entire address range. There's no happy outcome for this api in such a case so we choose not to take the overhead of checking.
- return valueLength <= span.Length && SpanHelpers.SequenceEqual(ref MemoryMarshal.GetReference(span), ref MemoryMarshal.GetReference(value), valueLength);
- }
- /// <summary>
- /// Determines whether the specified sequence appears at the start of the span.
- /// </summary>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool StartsWith<T>(this ReadOnlySpan<T> span, ReadOnlySpan<T> value)
- where T : IEquatable<T>
- {
- int valueLength = value.Length;
- if (default(T) != null && IsTypeComparableAsBytes<T>(out nuint size))
- return valueLength <= span.Length &&
- SpanHelpers.SequenceEqual(
- ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(span)),
- ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(value)),
- ((nuint)valueLength) * size); // If this multiplication overflows, the Span we got overflows the entire address range. There's no happy outcome for this api in such a case so we choose not to take the overhead of checking.
- return valueLength <= span.Length && SpanHelpers.SequenceEqual(ref MemoryMarshal.GetReference(span), ref MemoryMarshal.GetReference(value), valueLength);
- }
- /// <summary>
- /// Determines whether the specified sequence appears at the end of the span.
- /// </summary>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool EndsWith<T>(this Span<T> span, ReadOnlySpan<T> value)
- where T : IEquatable<T>
- {
- int spanLength = span.Length;
- int valueLength = value.Length;
- if (default(T) != null && IsTypeComparableAsBytes<T>(out nuint size))
- return valueLength <= spanLength &&
- SpanHelpers.SequenceEqual(
- ref Unsafe.As<T, byte>(ref Unsafe.Add(ref MemoryMarshal.GetReference(span), spanLength - valueLength)),
- ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(value)),
- ((nuint)valueLength) * size); // If this multiplication overflows, the Span we got overflows the entire address range. There's no happy outcome for this api in such a case so we choose not to take the overhead of checking.
- return valueLength <= spanLength &&
- SpanHelpers.SequenceEqual(
- ref Unsafe.Add(ref MemoryMarshal.GetReference(span), spanLength - valueLength),
- ref MemoryMarshal.GetReference(value),
- valueLength);
- }
- /// <summary>
- /// Determines whether the specified sequence appears at the end of the span.
- /// </summary>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool EndsWith<T>(this ReadOnlySpan<T> span, ReadOnlySpan<T> value)
- where T : IEquatable<T>
- {
- int spanLength = span.Length;
- int valueLength = value.Length;
- if (default(T) != null && IsTypeComparableAsBytes<T>(out nuint size))
- return valueLength <= spanLength &&
- SpanHelpers.SequenceEqual(
- ref Unsafe.As<T, byte>(ref Unsafe.Add(ref MemoryMarshal.GetReference(span), spanLength - valueLength)),
- ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(value)),
- ((nuint)valueLength) * size); // If this multiplication overflows, the Span we got overflows the entire address range. There's no happy outcome for this api in such a case so we choose not to take the overhead of checking.
- return valueLength <= spanLength &&
- SpanHelpers.SequenceEqual(
- ref Unsafe.Add(ref MemoryMarshal.GetReference(span), spanLength - valueLength),
- ref MemoryMarshal.GetReference(value),
- valueLength);
- }
- /// <summary>
- /// Returns an enumeration of <see cref="Rune"/> from the provided span.
- /// </summary>
- /// <remarks>
- /// Invalid sequences will be represented in the enumeration by <see cref="Rune.ReplacementChar"/>.
- /// </remarks>
- public static SpanRuneEnumerator EnumerateRunes(this ReadOnlySpan<char> span)
- {
- return new SpanRuneEnumerator(span);
- }
- /// <summary>
- /// Returns an enumeration of <see cref="Rune"/> from the provided span.
- /// </summary>
- /// <remarks>
- /// Invalid sequences will be represented in the enumeration by <see cref="Rune.ReplacementChar"/>.
- /// </remarks>
- public static SpanRuneEnumerator EnumerateRunes(this Span<char> span)
- {
- return new SpanRuneEnumerator(span);
- }
- /// <summary>
- /// Reverses the sequence of the elements in the entire span.
- /// </summary>
- public static void Reverse<T>(this Span<T> span)
- {
- if (span.Length <= 1)
- {
- return;
- }
- ref T first = ref MemoryMarshal.GetReference(span);
- ref T last = ref Unsafe.Add(ref Unsafe.Add(ref first, span.Length), -1);
- do
- {
- T temp = first;
- first = last;
- last = temp;
- first = ref Unsafe.Add(ref first, 1);
- last = ref Unsafe.Add(ref last, -1);
- } while (Unsafe.IsAddressLessThan(ref first, ref last));
- }
- /// <summary>
- /// Creates a new span over the target array.
- /// </summary>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Span<T> AsSpan<T>(this T[] array)
- {
- return new Span<T>(array);
- }
- /// <summary>
- /// Creates a new Span over the portion of the target array beginning
- /// at 'start' index and ending at 'end' index (exclusive).
- /// </summary>
- /// <param name="array">The target array.</param>
- /// <param name="start">The index at which to begin the Span.</param>
- /// <param name="length">The number of items in the Span.</param>
- /// <remarks>Returns default when <paramref name="array"/> is null.</remarks>
- /// <exception cref="System.ArrayTypeMismatchException">Thrown when <paramref name="array"/> is covariant and array's type is not exactly T[].</exception>
- /// <exception cref="System.ArgumentOutOfRangeException">
- /// Thrown when the specified <paramref name="start"/> or end index is not in the range (<0 or >=Length).
- /// </exception>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Span<T> AsSpan<T>(this T[] array, int start, int length)
- {
- return new Span<T>(array, start, length);
- }
- /// <summary>
- /// Creates a new span over the portion of the target array segment.
- /// </summary>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Span<T> AsSpan<T>(this ArraySegment<T> segment)
- {
- return new Span<T>(segment.Array, segment.Offset, segment.Count);
- }
- /// <summary>
- /// Creates a new Span over the portion of the target array beginning
- /// at 'start' index and ending at 'end' index (exclusive).
- /// </summary>
- /// <param name="segment">The target array.</param>
- /// <param name="start">The index at which to begin the Span.</param>
- /// <remarks>Returns default when <paramref name="segment"/> is null.</remarks>
- /// <exception cref="System.ArrayTypeMismatchException">Thrown when <paramref name="segment"/> is covariant and array's type is not exactly T[].</exception>
- /// <exception cref="System.ArgumentOutOfRangeException">
- /// Thrown when the specified <paramref name="start"/> or end index is not in the range (<0 or >=segment.Count).
- /// </exception>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Span<T> AsSpan<T>(this ArraySegment<T> segment, int start)
- {
- if (((uint)start) > (uint)segment.Count)
- ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
- return new Span<T>(segment.Array, segment.Offset + start, segment.Count - start);
- }
- /// <summary>
- /// Creates a new Span over the portion of the target array beginning
- /// at 'start' index and ending at 'end' index (exclusive).
- /// </summary>
- /// <param name="segment">The target array.</param>
- /// <param name="start">The index at which to begin the Span.</param>
- /// <param name="length">The number of items in the Span.</param>
- /// <remarks>Returns default when <paramref name="segment"/> is null.</remarks>
- /// <exception cref="System.ArrayTypeMismatchException">Thrown when <paramref name="segment"/> is covariant and array's type is not exactly T[].</exception>
- /// <exception cref="System.ArgumentOutOfRangeException">
- /// Thrown when the specified <paramref name="start"/> or end index is not in the range (<0 or >=segment.Count).
- /// </exception>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Span<T> AsSpan<T>(this ArraySegment<T> segment, int start, int length)
- {
- if (((uint)start) > (uint)segment.Count)
- ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
- if (((uint)length) > (uint)(segment.Count - start))
- ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.length);
- return new Span<T>(segment.Array, segment.Offset + start, length);
- }
- /// <summary>
- /// Creates a new memory over the target array.
- /// </summary>
- public static Memory<T> AsMemory<T>(this T[] array) => new Memory<T>(array);
- /// <summary>
- /// Creates a new memory over the portion of the target array beginning
- /// at 'start' index and ending at 'end' index (exclusive).
- /// </summary>
- /// <param name="array">The target array.</param>
- /// <param name="start">The index at which to begin the memory.</param>
- /// <remarks>Returns default when <paramref name="array"/> is null.</remarks>
- /// <exception cref="System.ArrayTypeMismatchException">Thrown when <paramref name="array"/> is covariant and array's type is not exactly T[].</exception>
- /// <exception cref="System.ArgumentOutOfRangeException">
- /// Thrown when the specified <paramref name="start"/> or end index is not in the range (<0 or >=array.Length).
- /// </exception>
- public static Memory<T> AsMemory<T>(this T[] array, int start) => new Memory<T>(array, start);
- /// <summary>
- /// Creates a new memory over the portion of the target array beginning
- /// at 'start' index and ending at 'end' index (exclusive).
- /// </summary>
- /// <param name="array">The target array.</param>
- /// <param name="start">The index at which to begin the memory.</param>
- /// <param name="length">The number of items in the memory.</param>
- /// <remarks>Returns default when <paramref name="array"/> is null.</remarks>
- /// <exception cref="System.ArrayTypeMismatchException">Thrown when <paramref name="array"/> is covariant and array's type is not exactly T[].</exception>
- /// <exception cref="System.ArgumentOutOfRangeException">
- /// Thrown when the specified <paramref name="start"/> or end index is not in the range (<0 or >=Length).
- /// </exception>
- public static Memory<T> AsMemory<T>(this T[] array, int start, int length) => new Memory<T>(array, start, length);
- /// <summary>
- /// Creates a new memory over the portion of the target array.
- /// </summary>
- public static Memory<T> AsMemory<T>(this ArraySegment<T> segment) => new Memory<T>(segment.Array, segment.Offset, segment.Count);
- /// <summary>
- /// Creates a new memory over the portion of the target array beginning
- /// at 'start' index and ending at 'end' index (exclusive).
- /// </summary>
- /// <param name="segment">The target array.</param>
- /// <param name="start">The index at which to begin the memory.</param>
- /// <remarks>Returns default when <paramref name="segment"/> is null.</remarks>
- /// <exception cref="System.ArrayTypeMismatchException">Thrown when <paramref name="segment"/> is covariant and array's type is not exactly T[].</exception>
- /// <exception cref="System.ArgumentOutOfRangeException">
- /// Thrown when the specified <paramref name="start"/> or end index is not in the range (<0 or >=segment.Count).
- /// </exception>
- public static Memory<T> AsMemory<T>(this ArraySegment<T> segment, int start)
- {
- if (((uint)start) > (uint)segment.Count)
- ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
- return new Memory<T>(segment.Array, segment.Offset + start, segment.Count - start);
- }
- /// <summary>
- /// Creates a new memory over the portion of the target array beginning
- /// at 'start' index and ending at 'end' index (exclusive).
- /// </summary>
- /// <param name="segment">The target array.</param>
- /// <param name="start">The index at which to begin the memory.</param>
- /// <param name="length">The number of items in the memory.</param>
- /// <remarks>Returns default when <paramref name="segment"/> is null.</remarks>
- /// <exception cref="System.ArrayTypeMismatchException">Thrown when <paramref name="segment"/> is covariant and array's type is not exactly T[].</exception>
- /// <exception cref="System.ArgumentOutOfRangeException">
- /// Thrown when the specified <paramref name="start"/> or end index is not in the range (<0 or >=segment.Count).
- /// </exception>
- public static Memory<T> AsMemory<T>(this ArraySegment<T> segment, int start, int length)
- {
- if (((uint)start) > (uint)segment.Count)
- ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
- if (((uint)length) > (uint)(segment.Count - start))
- ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.length);
- return new Memory<T>(segment.Array, segment.Offset + start, length);
- }
- /// <summary>
- /// Copies the contents of the array into the span. If the source
- /// and destinations overlap, this method behaves as if the original values in
- /// a temporary location before the destination is overwritten.
- ///
- ///<param name="source">The array to copy items from.</param>
- /// <param name="destination">The span to copy items into.</param>
- /// <exception cref="System.ArgumentException">
- /// Thrown when the destination Span is shorter than the source array.
- /// </exception>
- /// </summary>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void CopyTo<T>(this T[] source, Span<T> destination)
- {
- new ReadOnlySpan<T>(source).CopyTo(destination);
- }
- /// <summary>
- /// Copies the contents of the array into the memory. If the source
- /// and destinations overlap, this method behaves as if the original values are in
- /// a temporary location before the destination is overwritten.
- ///
- ///<param name="source">The array to copy items from.</param>
- /// <param name="destination">The memory to copy items into.</param>
- /// <exception cref="System.ArgumentException">
- /// Thrown when the destination is shorter than the source array.
- /// </exception>
- /// </summary>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void CopyTo<T>(this T[] source, Memory<T> destination)
- {
- source.CopyTo(destination.Span);
- }
- //
- // Overlaps
- // ========
- //
- // The following methods can be used to determine if two sequences
- // overlap in memory.
- //
- // Two sequences overlap if they have positions in common and neither
- // is empty. Empty sequences do not overlap with any other sequence.
- //
- // If two sequences overlap, the element offset is the number of
- // elements by which the second sequence is offset from the first
- // sequence (i.e., second minus first). An exception is thrown if the
- // number is not a whole number, which can happen when a sequence of a
- // smaller type is cast to a sequence of a larger type with unsafe code
- // or NonPortableCast. If the sequences do not overlap, the offset is
- // meaningless and arbitrarily set to zero.
- //
- // Implementation
- // --------------
- //
- // Implementing this correctly is quite tricky due of two problems:
- //
- // * If the sequences refer to two different objects on the managed
- // heap, the garbage collector can move them freely around or change
- // their relative order in memory.
- //
- // * The distance between two sequences can be greater than
- // int.MaxValue (on a 32-bit system) or long.MaxValue (on a 64-bit
- // system).
- //
- // (For simplicity, the following text assumes a 32-bit system, but
- // everything also applies to a 64-bit system if every 32 is replaced a
- // 64.)
- //
- // The first problem is solved by calculating the distance with exactly
- // one atomic operation. If the garbage collector happens to move the
- // sequences afterwards and the sequences overlapped before, they will
- // still overlap after the move and their distance hasn't changed. If
- // the sequences did not overlap, the distance can change but the
- // sequences still won't overlap.
- //
- // The second problem is solved by making all addresses relative to the
- // start of the first sequence and performing all operations in
- // unsigned integer arithmetic modulo 2³².
- //
- // Example
- // -------
- //
- // Let's say there are two sequences, x and y. Let
- //
- // ref T xRef = MemoryMarshal.GetReference(x)
- // uint xLength = x.Length * Unsafe.SizeOf<T>()
- // ref T yRef = MemoryMarshal.GetReference(y)
- // uint yLength = y.Length * Unsafe.SizeOf<T>()
- //
- // Visually, the two sequences are located somewhere in the 32-bit
- // address space as follows:
- //
- // [----------------------------------------------) normal address space
- // 0 2³²
- // [------------------) first sequence
- // xRef xRef + xLength
- // [--------------------------) . second sequence
- // yRef . yRef + yLength
- // : . . .
- // : . . .
- // . . .
- // . . .
- // . . .
- // [----------------------------------------------) relative address space
- // 0 . . 2³²
- // [------------------) : first sequence
- // x1 . x2 :
- // -------------) [------------- second sequence
- // y2 y1
- //
- // The idea is to make all addresses relative to xRef: Let x1 be the
- // start address of x in this relative address space, x2 the end
- // address of x, y1 the start address of y, and y2 the end address of
- // y:
- //
- // nuint x1 = 0
- // nuint x2 = xLength
- // nuint y1 = (nuint)Unsafe.ByteOffset(xRef, yRef)
- // nuint y2 = y1 + yLength
- //
- // xRef relative to xRef is 0.
- //
- // x2 is simply x1 + xLength. This cannot overflow.
- //
- // yRef relative to xRef is (yRef - xRef). If (yRef - xRef) is
- // negative, casting it to an unsigned 32-bit integer turns it into
- // (yRef - xRef + 2³²). So, in the example above, y1 moves to the right
- // of x2.
- //
- // y2 is simply y1 + yLength. Note that this can overflow, as in the
- // example above, which must be avoided.
- //
- // The two sequences do *not* overlap if y is entirely in the space
- // right of x in the relative address space. (It can't be left of it!)
- //
- // (y1 >= x2) && (y2 <= 2³²)
- //
- // Inversely, they do overlap if
- //
- // (y1 < x2) || (y2 > 2³²)
- //
- // After substituting x2 and y2 with their respective definition:
- //
- // == (y1 < xLength) || (y1 + yLength > 2³²)
- //
- // Since yLength can't be greater than the size of the address space,
- // the overflow can be avoided as follows:
- //
- // == (y1 < xLength) || (y1 > 2³² - yLength)
- //
- // However, 2³² cannot be stored in an unsigned 32-bit integer, so one
- // more change is needed to keep doing everything with unsigned 32-bit
- // integers:
- //
- // == (y1 < xLength) || (y1 > -yLength)
- //
- // Due to modulo arithmetic, this gives exactly same result *except* if
- // yLength is zero, since 2³² - 0 is 0 and not 2³². So the case
- // y.IsEmpty must be handled separately first.
- //
- /// <summary>
- /// Determines whether two sequences overlap in memory.
- /// </summary>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool Overlaps<T>(this Span<T> span, ReadOnlySpan<T> other)
- {
- return Overlaps((ReadOnlySpan<T>)span, other);
- }
- /// <summary>
- /// Determines whether two sequences overlap in memory and outputs the element offset.
- /// </summary>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool Overlaps<T>(this Span<T> span, ReadOnlySpan<T> other, out int elementOffset)
- {
- return Overlaps((ReadOnlySpan<T>)span, other, out elementOffset);
- }
- /// <summary>
- /// Determines whether two sequences overlap in memory.
- /// </summary>
- public static bool Overlaps<T>(this ReadOnlySpan<T> span, ReadOnlySpan<T> other)
- {
- if (span.IsEmpty || other.IsEmpty)
- {
- return false;
- }
- IntPtr byteOffset = Unsafe.ByteOffset(
- ref MemoryMarshal.GetReference(span),
- ref MemoryMarshal.GetReference(other));
- if (Unsafe.SizeOf<IntPtr>() == sizeof(int))
- {
- return (uint)byteOffset < (uint)(span.Length * Unsafe.SizeOf<T>()) ||
- (uint)byteOffset > (uint)-(other.Length * Unsafe.SizeOf<T>());
- }
- else
- {
- return (ulong)byteOffset < (ulong)((long)span.Length * Unsafe.SizeOf<T>()) ||
- (ulong)byteOffset > (ulong)-((long)other.Length * Unsafe.SizeOf<T>());
- }
- }
- /// <summary>
- /// Determines whether two sequences overlap in memory and outputs the element offset.
- /// </summary>
- public static bool Overlaps<T>(this ReadOnlySpan<T> span, ReadOnlySpan<T> other, out int elementOffset)
- {
- if (span.IsEmpty || other.IsEmpty)
- {
- elementOffset = 0;
- return false;
- }
- IntPtr byteOffset = Unsafe.ByteOffset(
- ref MemoryMarshal.GetReference(span),
- ref MemoryMarshal.GetReference(other));
- if (Unsafe.SizeOf<IntPtr>() == sizeof(int))
- {
- if ((uint)byteOffset < (uint)(span.Length * Unsafe.SizeOf<T>()) ||
- (uint)byteOffset > (uint)-(other.Length * Unsafe.SizeOf<T>()))
- {
- if ((int)byteOffset % Unsafe.SizeOf<T>() != 0)
- ThrowHelper.ThrowArgumentException_OverlapAlignmentMismatch();
- elementOffset = (int)byteOffset / Unsafe.SizeOf<T>();
- return true;
- }
- else
- {
- elementOffset = 0;
- return false;
- }
- }
- else
- {
- if ((ulong)byteOffset < (ulong)((long)span.Length * Unsafe.SizeOf<T>()) ||
- (ulong)byteOffset > (ulong)-((long)other.Length * Unsafe.SizeOf<T>()))
- {
- if ((long)byteOffset % Unsafe.SizeOf<T>() != 0)
- ThrowHelper.ThrowArgumentException_OverlapAlignmentMismatch();
- elementOffset = (int)((long)byteOffset / Unsafe.SizeOf<T>());
- return true;
- }
- else
- {
- elementOffset = 0;
- return false;
- }
- }
- }
- /// <summary>
- /// Searches an entire sorted <see cref="Span{T}"/> for a value
- /// using the specified <see cref="IComparable{T}"/> generic interface.
- /// </summary>
- /// <typeparam name="T">The element type of the span.</typeparam>
- /// <param name="span">The sorted <see cref="Span{T}"/> to search.</param>
- /// <param name="comparable">The <see cref="IComparable{T}"/> to use when comparing.</param>
- /// <returns>
- /// The zero-based index of <paramref name="comparable"/> in the sorted <paramref name="span"/>,
- /// if <paramref name="comparable"/> is found; otherwise, a negative number that is the bitwise complement
- /// of the index of the next element that is larger than <paramref name="comparable"/> or, if there is
- /// no larger element, the bitwise complement of <see cref="Span{T}.Length"/>.
- /// </returns>
- /// <exception cref="T:System.ArgumentNullException">
- /// <paramref name = "comparable" /> is <see langword="null"/> .
- /// </exception>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static int BinarySearch<T>(
- this Span<T> span, IComparable<T> comparable)
- {
- return BinarySearch<T, IComparable<T>>(span, comparable);
- }
- /// <summary>
- /// Searches an entire sorted <see cref="Span{T}"/> for a value
- /// using the specified <typeparamref name="TComparable"/> generic type.
- /// </summary>
- /// <typeparam name="T">The element type of the span.</typeparam>
- /// <typeparam name="TComparable">The specific type of <see cref="IComparable{T}"/>.</typeparam>
- /// <param name="span">The sorted <see cref="Span{T}"/> to search.</param>
- /// <param name="comparable">The <typeparamref name="TComparable"/> to use when comparing.</param>
- /// <returns>
- /// The zero-based index of <paramref name="comparable"/> in the sorted <paramref name="span"/>,
- /// if <paramref name="comparable"/> is found; otherwise, a negative number that is the bitwise complement
- /// of the index of the next element that is larger than <paramref name="comparable"/> or, if there is
- /// no larger element, the bitwise complement of <see cref="Span{T}.Length"/>.
- /// </returns>
- /// <exception cref="T:System.ArgumentNullException">
- /// <paramref name = "comparable" /> is <see langword="null"/> .
- /// </exception>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static int BinarySearch<T, TComparable>(
- this Span<T> span, TComparable comparable)
- where TComparable : IComparable<T>
- {
- return BinarySearch((ReadOnlySpan<T>)span, comparable);
- }
- /// <summary>
- /// Searches an entire sorted <see cref="Span{T}"/> for the specified <paramref name="value"/>
- /// using the specified <typeparamref name="TComparer"/> generic type.
- /// </summary>
- /// <typeparam name="T">The element type of the span.</typeparam>
- /// <typeparam name="TComparer">The specific type of <see cref="IComparer{T}"/>.</typeparam>
- /// <param name="span">The sorted <see cref="Span{T}"/> to search.</param>
- /// <param name="value">The object to locate. The value can be null for reference types.</param>
- /// <param name="comparer">The <typeparamref name="TComparer"/> to use when comparing.</param>
- /// /// <returns>
- /// The zero-based index of <paramref name="value"/> in the sorted <paramref name="span"/>,
- /// if <paramref name="value"/> is found; otherwise, a negative number that is the bitwise complement
- /// of the index of the next element that is larger than <paramref name="value"/> or, if there is
- /// no larger element, the bitwise complement of <see cref="Span{T}.Length"/>.
- /// </returns>
- /// <exception cref="T:System.ArgumentNullException">
- /// <paramref name = "comparer" /> is <see langword="null"/> .
- /// </exception>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static int BinarySearch<T, TComparer>(
- this Span<T> span, T value, TComparer comparer)
- where TComparer : IComparer<T>
- {
- return BinarySearch((ReadOnlySpan<T>)span, value, comparer);
- }
- /// <summary>
- /// Searches an entire sorted <see cref="ReadOnlySpan{T}"/> for a value
- /// using the specified <see cref="IComparable{T}"/> generic interface.
- /// </summary>
- /// <typeparam name="T">The element type of the span.</typeparam>
- /// <param name="span">The sorted <see cref="ReadOnlySpan{T}"/> to search.</param>
- /// <param name="comparable">The <see cref="IComparable{T}"/> to use when comparing.</param>
- /// <returns>
- /// The zero-based index of <paramref name="comparable"/> in the sorted <paramref name="span"/>,
- /// if <paramref name="comparable"/> is found; otherwise, a negative number that is the bitwise complement
- /// of the index of the next element that is larger than <paramref name="comparable"/> or, if there is
- /// no larger element, the bitwise complement of <see cref="ReadOnlySpan{T}.Length"/>.
- /// </returns>
- /// <exception cref="T:System.ArgumentNullException">
- /// <paramref name = "comparable" /> is <see langword="null"/> .
- /// </exception>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static int BinarySearch<T>(
- this ReadOnlySpan<T> span, IComparable<T> comparable)
- {
- return BinarySearch<T, IComparable<T>>(span, comparable);
- }
- /// <summary>
- /// Searches an entire sorted <see cref="ReadOnlySpan{T}"/> for a value
- /// using the specified <typeparamref name="TComparable"/> generic type.
- /// </summary>
- /// <typeparam name="T">The element type of the span.</typeparam>
- /// <typeparam name="TComparable">The specific type of <see cref="IComparable{T}"/>.</typeparam>
- /// <param name="span">The sorted <see cref="ReadOnlySpan{T}"/> to search.</param>
- /// <param name="comparable">The <typeparamref name="TComparable"/> to use when comparing.</param>
- /// <returns>
- /// The zero-based index of <paramref name="comparable"/> in the sorted <paramref name="span"/>,
- /// if <paramref name="comparable"/> is found; otherwise, a negative number that is the bitwise complement
- /// of the index of the next element that is larger than <paramref name="comparable"/> or, if there is
- /// no larger element, the bitwise complement of <see cref="ReadOnlySpan{T}.Length"/>.
- /// </returns>
- /// <exception cref="T:System.ArgumentNullException">
- /// <paramref name = "comparable" /> is <see langword="null"/> .
- /// </exception>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static int BinarySearch<T, TComparable>(
- this ReadOnlySpan<T> span, TComparable comparable)
- where TComparable : IComparable<T>
- {
- return SpanHelpers.BinarySearch(span, comparable);
- }
- /// <summary>
- /// Searches an entire sorted <see cref="ReadOnlySpan{T}"/> for the specified <paramref name="value"/>
- /// using the specified <typeparamref name="TComparer"/> generic type.
- /// </summary>
- /// <typeparam name="T">The element type of the span.</typeparam>
- /// <typeparam name="TComparer">The specific type of <see cref="IComparer{T}"/>.</typeparam>
- /// <param name="span">The sorted <see cref="ReadOnlySpan{T}"/> to search.</param>
- /// <param name="value">The object to locate. The value can be null for reference types.</param>
- /// <param name="comparer">The <typeparamref name="TComparer"/> to use when comparing.</param>
- /// /// <returns>
- /// The zero-based index of <paramref name="value"/> in the sorted <paramref name="span"/>,
- /// if <paramref name="value"/> is found; otherwise, a negative number that is the bitwise complement
- /// of the index of the next element that is larger than <paramref name="value"/> or, if there is
- /// no larger element, the bitwise complement of <see cref="ReadOnlySpan{T}.Length"/>.
- /// </returns>
- /// <exception cref="T:System.ArgumentNullException">
- /// <paramref name = "comparer" /> is <see langword="null"/> .
- /// </exception>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static int BinarySearch<T, TComparer>(
- this ReadOnlySpan<T> span, T value, TComparer comparer)
- where TComparer : IComparer<T>
- {
- if (comparer == null)
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.comparer);
- var comparable = new SpanHelpers.ComparerComparable<T, TComparer>(
- value, comparer);
- return BinarySearch(span, comparable);
- }
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static bool IsTypeComparableAsBytes<T>(out nuint size)
- {
- if (typeof(T) == typeof(byte) || typeof(T) == typeof(sbyte))
- {
- size = sizeof(byte);
- return true;
- }
- if (typeof(T) == typeof(char) || typeof(T) == typeof(short) || typeof(T) == typeof(ushort))
- {
- size = sizeof(char);
- return true;
- }
- if (typeof(T) == typeof(int) || typeof(T) == typeof(uint))
- {
- size = sizeof(int);
- return true;
- }
- if (typeof(T) == typeof(long) || typeof(T) == typeof(ulong))
- {
- size = sizeof(long);
- return true;
- }
- size = default;
- return false;
- }
- }
- }
|