| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145 |
- // 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;
- using System.Collections.Generic;
- using System.Collections.ObjectModel;
- using System.Diagnostics;
- using System.Runtime.CompilerServices;
- using Internal.Runtime.CompilerServices;
- namespace System
- {
- [Serializable]
- [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
- public abstract partial class Array : ICloneable, IList, IStructuralComparable, IStructuralEquatable
- {
- // We impose limits on maximum array lenght in each dimension to allow efficient
- // implementation of advanced range check elimination in future.
- // Keep in sync with vm\gcscan.cpp and HashHelpers.MaxPrimeArrayLength.
- // The constants are defined in this method: inline SIZE_T MaxArrayLength(SIZE_T componentSize) from gcscan
- // We have different max sizes for arrays with elements of size 1 for backwards compatibility
- internal const int MaxArrayLength = 0X7FEFFFFF;
- internal const int MaxByteArrayLength = 0x7FFFFFC7;
- // This ctor exists solely to prevent C# from generating a protected .ctor that violates the surface area. I really want this to be a
- // "protected-and-internal" rather than "internal" but C# has no keyword for the former.
- internal Array() { }
- public static ReadOnlyCollection<T> AsReadOnly<T>(T[] array)
- {
- if (array == null)
- {
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
- }
- // T[] implements IList<T>.
- return new ReadOnlyCollection<T>(array);
- }
- public static void Resize<T>(ref T[] array, int newSize)
- {
- if (newSize < 0)
- ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.newSize, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum);
- T[] larray = array;
- if (larray == null)
- {
- array = new T[newSize];
- return;
- }
- if (larray.Length != newSize)
- {
- T[] newArray = new T[newSize];
- Copy(larray, 0, newArray, 0, larray.Length > newSize ? newSize : larray.Length);
- array = newArray;
- }
- }
- public static Array CreateInstance(Type elementType, params long[] lengths)
- {
- if (lengths == null)
- {
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.lengths);
- }
- if (lengths.Length == 0)
- ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_NeedAtLeast1Rank);
- int[] intLengths = new int[lengths.Length];
- for (int i = 0; i < lengths.Length; ++i)
- {
- long len = lengths[i];
- int ilen = (int)len;
- if (len != ilen)
- ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.len, ExceptionResource.ArgumentOutOfRange_HugeArrayNotSupported);
- intLengths[i] = ilen;
- }
- return Array.CreateInstance(elementType, intLengths);
- }
- public static void Copy(Array sourceArray, Array destinationArray, long length)
- {
- int ilength = (int)length;
- if (length != ilength)
- ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.length, ExceptionResource.ArgumentOutOfRange_HugeArrayNotSupported);
- Copy(sourceArray, destinationArray, ilength);
- }
- public static void Copy(Array sourceArray, long sourceIndex, Array destinationArray, long destinationIndex, long length)
- {
- int isourceIndex = (int)sourceIndex;
- int idestinationIndex = (int)destinationIndex;
- int ilength = (int)length;
- if (sourceIndex != isourceIndex)
- ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.sourceIndex, ExceptionResource.ArgumentOutOfRange_HugeArrayNotSupported);
- if (destinationIndex != idestinationIndex)
- ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.destinationIndex, ExceptionResource.ArgumentOutOfRange_HugeArrayNotSupported);
- if (length != ilength)
- ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.length, ExceptionResource.ArgumentOutOfRange_HugeArrayNotSupported);
- Copy(sourceArray, isourceIndex, destinationArray, idestinationIndex, ilength);
- }
- public object GetValue(long index)
- {
- int iindex = (int)index;
- if (index != iindex)
- ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index, ExceptionResource.ArgumentOutOfRange_HugeArrayNotSupported);
- return this.GetValue(iindex);
- }
- public object GetValue(long index1, long index2)
- {
- int iindex1 = (int)index1;
- int iindex2 = (int)index2;
- if (index1 != iindex1)
- ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index1, ExceptionResource.ArgumentOutOfRange_HugeArrayNotSupported);
- if (index2 != iindex2)
- ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index2, ExceptionResource.ArgumentOutOfRange_HugeArrayNotSupported);
- return this.GetValue(iindex1, iindex2);
- }
- public object GetValue(long index1, long index2, long index3)
- {
- int iindex1 = (int)index1;
- int iindex2 = (int)index2;
- int iindex3 = (int)index3;
- if (index1 != iindex1)
- ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index1, ExceptionResource.ArgumentOutOfRange_HugeArrayNotSupported);
- if (index2 != iindex2)
- ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index2, ExceptionResource.ArgumentOutOfRange_HugeArrayNotSupported);
- if (index3 != iindex3)
- ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index3, ExceptionResource.ArgumentOutOfRange_HugeArrayNotSupported);
- return this.GetValue(iindex1, iindex2, iindex3);
- }
- public object GetValue(params long[] indices)
- {
- if (indices == null)
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.indices);
- if (Rank != indices.Length)
- ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_RankIndices);
- int[] intIndices = new int[indices.Length];
- for (int i = 0; i < indices.Length; ++i)
- {
- long index = indices[i];
- int iindex = (int)index;
- if (index != iindex)
- ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index, ExceptionResource.ArgumentOutOfRange_HugeArrayNotSupported);
- intIndices[i] = iindex;
- }
- return this.GetValue(intIndices);
- }
- public void SetValue(object value, long index)
- {
- int iindex = (int)index;
- if (index != iindex)
- ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index, ExceptionResource.ArgumentOutOfRange_HugeArrayNotSupported);
- this.SetValue(value, iindex);
- }
- public void SetValue(object value, long index1, long index2)
- {
- int iindex1 = (int)index1;
- int iindex2 = (int)index2;
- if (index1 != iindex1)
- ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index1, ExceptionResource.ArgumentOutOfRange_HugeArrayNotSupported);
- if (index2 != iindex2)
- ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index2, ExceptionResource.ArgumentOutOfRange_HugeArrayNotSupported);
- this.SetValue(value, iindex1, iindex2);
- }
- public void SetValue(object value, long index1, long index2, long index3)
- {
- int iindex1 = (int)index1;
- int iindex2 = (int)index2;
- int iindex3 = (int)index3;
- if (index1 != iindex1)
- ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index1, ExceptionResource.ArgumentOutOfRange_HugeArrayNotSupported);
- if (index2 != iindex2)
- ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index2, ExceptionResource.ArgumentOutOfRange_HugeArrayNotSupported);
- if (index3 != iindex3)
- ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index3, ExceptionResource.ArgumentOutOfRange_HugeArrayNotSupported);
- this.SetValue(value, iindex1, iindex2, iindex3);
- }
- public void SetValue(object value, params long[] indices)
- {
- if (indices == null)
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.indices);
- if (Rank != indices.Length)
- ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_RankIndices);
- int[] intIndices = new int[indices.Length];
- for (int i = 0; i < indices.Length; ++i)
- {
- long index = indices[i];
- int iindex = (int)index;
- if (index != iindex)
- ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index, ExceptionResource.ArgumentOutOfRange_HugeArrayNotSupported);
- intIndices[i] = iindex;
- }
- this.SetValue(value, intIndices);
- }
- private static int GetMedian(int low, int hi)
- {
- // Note both may be negative, if we are dealing with arrays w/ negative lower bounds.
- Debug.Assert(low <= hi);
- Debug.Assert(hi - low >= 0, "Length overflow!");
- return low + ((hi - low) >> 1);
- }
- public long GetLongLength(int dimension)
- {
- //This method should throw an IndexOufOfRangeException for compat if dimension < 0 or >= Rank
- return GetLength(dimension);
- }
- // Number of elements in the Array.
- int ICollection.Count
- { get { return Length; } }
- // Returns an object appropriate for synchronizing access to this
- // Array.
- public object SyncRoot
- { get { return this; } }
- // Is this Array read-only?
- public bool IsReadOnly
- { get { return false; } }
- public bool IsFixedSize
- {
- get { return true; }
- }
- // Is this Array synchronized (i.e., thread-safe)? If you want a synchronized
- // collection, you can use SyncRoot as an object to synchronize your
- // collection with. You could also call GetSynchronized()
- // to get a synchronized wrapper around the Array.
- public bool IsSynchronized
- { get { return false; } }
- object IList.this[int index]
- {
- get { return GetValue(index); }
- set { SetValue(value, index); }
- }
- int IList.Add(object value)
- {
- ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_FixedSizeCollection);
- return default;
- }
- bool IList.Contains(object value)
- {
- return Array.IndexOf(this, value) >= this.GetLowerBound(0);
- }
- void IList.Clear()
- {
- Array.Clear(this, this.GetLowerBound(0), this.Length);
- }
- int IList.IndexOf(object value)
- {
- return Array.IndexOf(this, value);
- }
- void IList.Insert(int index, object value)
- {
- ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_FixedSizeCollection);
- }
- void IList.Remove(object value)
- {
- ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_FixedSizeCollection);
- }
- void IList.RemoveAt(int index)
- {
- ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_FixedSizeCollection);
- }
- // Make a new array which is a shallow copy of the original array.
- //
- public object Clone()
- {
- return MemberwiseClone();
- }
- int IStructuralComparable.CompareTo(object other, IComparer comparer)
- {
- if (other == null)
- {
- return 1;
- }
- Array o = other as Array;
- if (o == null || this.Length != o.Length)
- {
- ThrowHelper.ThrowArgumentException(ExceptionResource.ArgumentException_OtherNotArrayOfCorrectLength, ExceptionArgument.other);
- }
- int i = 0;
- int c = 0;
- while (i < o.Length && c == 0)
- {
- object left = GetValue(i);
- object right = o.GetValue(i);
- c = comparer.Compare(left, right);
- i++;
- }
- return c;
- }
- bool IStructuralEquatable.Equals(object other, IEqualityComparer comparer)
- {
- if (other == null)
- {
- return false;
- }
- if (object.ReferenceEquals(this, other))
- {
- return true;
- }
- if (!(other is Array o) || o.Length != this.Length)
- {
- return false;
- }
- int i = 0;
- while (i < o.Length)
- {
- object left = GetValue(i);
- object right = o.GetValue(i);
- if (!comparer.Equals(left, right))
- {
- return false;
- }
- i++;
- }
- return true;
- }
- private static int CombineHashCodes(int h1, int h2)
- {
- return (((h1 << 5) + h1) ^ h2);
- }
- int IStructuralEquatable.GetHashCode(IEqualityComparer comparer)
- {
- if (comparer == null)
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.comparer);
- int ret = 0;
- for (int i = (this.Length >= 8 ? this.Length - 8 : 0); i < this.Length; i++)
- {
- ret = CombineHashCodes(ret, comparer.GetHashCode(GetValue(i)));
- }
- return ret;
- }
- // Searches an array for a given element using a binary search algorithm.
- // Elements of the array are compared to the search value using the
- // IComparable interface, which must be implemented by all elements
- // of the array and the given search value. This method assumes that the
- // array is already sorted according to the IComparable interface;
- // if this is not the case, the result will be incorrect.
- //
- // The method returns the index of the given value in the array. If the
- // array does not contain the given value, the method returns a negative
- // integer. The bitwise complement operator (~) can be applied to a
- // negative result to produce the index of the first element (if any) that
- // is larger than the given search value.
- //
- public static int BinarySearch(Array array, object value)
- {
- if (array == null)
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
- int lb = array.GetLowerBound(0);
- return BinarySearch(array, lb, array.Length, value, null);
- }
- // Searches a section of an array for a given element using a binary search
- // algorithm. Elements of the array are compared to the search value using
- // the IComparable interface, which must be implemented by all
- // elements of the array and the given search value. This method assumes
- // that the array is already sorted according to the IComparable
- // interface; if this is not the case, the result will be incorrect.
- //
- // The method returns the index of the given value in the array. If the
- // array does not contain the given value, the method returns a negative
- // integer. The bitwise complement operator (~) can be applied to a
- // negative result to produce the index of the first element (if any) that
- // is larger than the given search value.
- //
- public static int BinarySearch(Array array, int index, int length, object value)
- {
- return BinarySearch(array, index, length, value, null);
- }
- // Searches an array for a given element using a binary search algorithm.
- // Elements of the array are compared to the search value using the given
- // IComparer interface. If comparer is null, elements of the
- // array are compared to the search value using the IComparable
- // interface, which in that case must be implemented by all elements of the
- // array and the given search value. This method assumes that the array is
- // already sorted; if this is not the case, the result will be incorrect.
- //
- // The method returns the index of the given value in the array. If the
- // array does not contain the given value, the method returns a negative
- // integer. The bitwise complement operator (~) can be applied to a
- // negative result to produce the index of the first element (if any) that
- // is larger than the given search value.
- //
- public static int BinarySearch(Array array, object value, IComparer comparer)
- {
- if (array == null)
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
- return BinarySearch(array, array.GetLowerBound(0), array.Length, value, comparer);
- }
- // Searches a section of an array for a given element using a binary search
- // algorithm. Elements of the array are compared to the search value using
- // the given IComparer interface. If comparer is null,
- // elements of the array are compared to the search value using the
- // IComparable interface, which in that case must be implemented by
- // all elements of the array and the given search value. This method
- // assumes that the array is already sorted; if this is not the case, the
- // result will be incorrect.
- //
- // The method returns the index of the given value in the array. If the
- // array does not contain the given value, the method returns a negative
- // integer. The bitwise complement operator (~) can be applied to a
- // negative result to produce the index of the first element (if any) that
- // is larger than the given search value.
- //
- public static int BinarySearch(Array array, int index, int length, object value, IComparer comparer)
- {
- if (array == null)
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
- int lb = array.GetLowerBound(0);
- if (index < lb)
- ThrowHelper.ThrowIndexArgumentOutOfRange_NeedNonNegNumException();
- if (length < 0)
- ThrowHelper.ThrowLengthArgumentOutOfRange_ArgumentOutOfRange_NeedNonNegNum();
- if (array.Length - (index - lb) < length)
- ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidOffLen);
- if (array.Rank != 1)
- ThrowHelper.ThrowRankException(ExceptionResource.Rank_MultiDimNotSupported);
- if (comparer == null) comparer = Comparer.Default;
- #if CORECLR
- if (comparer == Comparer.Default)
- {
- int retval;
- bool r = TrySZBinarySearch(array, index, length, value, out retval);
- if (r)
- return retval;
- }
- #endif
- int lo = index;
- int hi = index + length - 1;
- if (array is object[] objArray)
- {
- while (lo <= hi)
- {
- // i might overflow if lo and hi are both large positive numbers.
- int i = GetMedian(lo, hi);
- int c;
- try
- {
- c = comparer.Compare(objArray[i], value);
- }
- catch (Exception e)
- {
- ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_IComparerFailed, e);
- return default;
- }
- if (c == 0) return i;
- if (c < 0)
- {
- lo = i + 1;
- }
- else
- {
- hi = i - 1;
- }
- }
- }
- else
- {
- while (lo <= hi)
- {
- int i = GetMedian(lo, hi);
- int c;
- try
- {
- c = comparer.Compare(array.GetValue(i), value);
- }
- catch (Exception e)
- {
- ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_IComparerFailed, e);
- return default;
- }
- if (c == 0) return i;
- if (c < 0)
- {
- lo = i + 1;
- }
- else
- {
- hi = i - 1;
- }
- }
- }
- return ~lo;
- }
- public static int BinarySearch<T>(T[] array, T value)
- {
- if (array == null)
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
- return BinarySearch<T>(array, 0, array.Length, value, null);
- }
- public static int BinarySearch<T>(T[] array, T value, System.Collections.Generic.IComparer<T> comparer)
- {
- if (array == null)
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
- return BinarySearch<T>(array, 0, array.Length, value, comparer);
- }
- public static int BinarySearch<T>(T[] array, int index, int length, T value)
- {
- return BinarySearch<T>(array, index, length, value, null);
- }
- public static int BinarySearch<T>(T[] array, int index, int length, T value, System.Collections.Generic.IComparer<T> comparer)
- {
- if (array == null)
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
- if (index < 0)
- ThrowHelper.ThrowIndexArgumentOutOfRange_NeedNonNegNumException();
- if (length < 0)
- ThrowHelper.ThrowLengthArgumentOutOfRange_ArgumentOutOfRange_NeedNonNegNum();
- if (array.Length - index < length)
- ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidOffLen);
- return ArraySortHelper<T>.Default.BinarySearch(array, index, length, value, comparer);
- }
- public static TOutput[] ConvertAll<TInput, TOutput>(TInput[] array, Converter<TInput, TOutput> converter)
- {
- if (array == null)
- {
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
- }
- if (converter == null)
- {
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.converter);
- }
- TOutput[] newArray = new TOutput[array.Length];
- for (int i = 0; i < array.Length; i++)
- {
- newArray[i] = converter(array[i]);
- }
- return newArray;
- }
- // CopyTo copies a collection into an Array, starting at a particular
- // index into the array.
- //
- // This method is to support the ICollection interface, and calls
- // Array.Copy internally. If you aren't using ICollection explicitly,
- // call Array.Copy to avoid an extra indirection.
- //
- public void CopyTo(Array array, int index)
- {
- if (array != null && array.Rank != 1)
- ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_RankMultiDimNotSupported);
- // Note: Array.Copy throws a RankException and we want a consistent ArgumentException for all the IList CopyTo methods.
- Array.Copy(this, GetLowerBound(0), array, index, Length);
- }
- public void CopyTo(Array array, long index)
- {
- int iindex = (int)index;
- if (index != iindex)
- ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index, ExceptionResource.ArgumentOutOfRange_HugeArrayNotSupported);
- this.CopyTo(array, iindex);
- }
- private static class EmptyArray<T>
- {
- internal static readonly T[] Value = new T[0];
- }
- public static T[] Empty<T>()
- {
- return EmptyArray<T>.Value;
- }
- public static bool Exists<T>(T[] array, Predicate<T> match)
- {
- return Array.FindIndex(array, match) != -1;
- }
- public static void Fill<T>(T[] array, T value)
- {
- if (array == null)
- {
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
- }
- for (int i = 0; i < array.Length; i++)
- {
- array[i] = value;
- }
- }
- public static void Fill<T>(T[] array, T value, int startIndex, int count)
- {
- if (array == null)
- {
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
- }
- if (startIndex < 0 || startIndex > array.Length)
- {
- ThrowHelper.ThrowStartIndexArgumentOutOfRange_ArgumentOutOfRange_Index();
- }
- if (count < 0 || startIndex > array.Length - count)
- {
- ThrowHelper.ThrowCountArgumentOutOfRange_ArgumentOutOfRange_Count();
- }
- for (int i = startIndex; i < startIndex + count; i++)
- {
- array[i] = value;
- }
- }
- public static T Find<T>(T[] array, Predicate<T> match)
- {
- if (array == null)
- {
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
- }
- if (match == null)
- {
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match);
- }
- for (int i = 0; i < array.Length; i++)
- {
- if (match(array[i]))
- {
- return array[i];
- }
- }
- return default;
- }
- public static T[] FindAll<T>(T[] array, Predicate<T> match)
- {
- if (array == null)
- {
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
- }
- if (match == null)
- {
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match);
- }
- List<T> list = new List<T>();
- for (int i = 0; i < array.Length; i++)
- {
- if (match(array[i]))
- {
- list.Add(array[i]);
- }
- }
- return list.ToArray();
- }
- public static int FindIndex<T>(T[] array, Predicate<T> match)
- {
- if (array == null)
- {
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
- }
- return FindIndex(array, 0, array.Length, match);
- }
- public static int FindIndex<T>(T[] array, int startIndex, Predicate<T> match)
- {
- if (array == null)
- {
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
- }
- return FindIndex(array, startIndex, array.Length - startIndex, match);
- }
- public static int FindIndex<T>(T[] array, int startIndex, int count, Predicate<T> match)
- {
- if (array == null)
- {
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
- }
- if (startIndex < 0 || startIndex > array.Length)
- {
- ThrowHelper.ThrowStartIndexArgumentOutOfRange_ArgumentOutOfRange_Index();
- }
- if (count < 0 || startIndex > array.Length - count)
- {
- ThrowHelper.ThrowCountArgumentOutOfRange_ArgumentOutOfRange_Count();
- }
- if (match == null)
- {
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match);
- }
- int endIndex = startIndex + count;
- for (int i = startIndex; i < endIndex; i++)
- {
- if (match(array[i])) return i;
- }
- return -1;
- }
- public static T FindLast<T>(T[] array, Predicate<T> match)
- {
- if (array == null)
- {
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
- }
- if (match == null)
- {
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match);
- }
- for (int i = array.Length - 1; i >= 0; i--)
- {
- if (match(array[i]))
- {
- return array[i];
- }
- }
- return default;
- }
- public static int FindLastIndex<T>(T[] array, Predicate<T> match)
- {
- if (array == null)
- {
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
- }
- return FindLastIndex(array, array.Length - 1, array.Length, match);
- }
- public static int FindLastIndex<T>(T[] array, int startIndex, Predicate<T> match)
- {
- if (array == null)
- {
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
- }
- return FindLastIndex(array, startIndex, startIndex + 1, match);
- }
- public static int FindLastIndex<T>(T[] array, int startIndex, int count, Predicate<T> match)
- {
- if (array == null)
- {
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
- }
- if (match == null)
- {
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match);
- }
- if (array.Length == 0)
- {
- // Special case for 0 length List
- if (startIndex != -1)
- {
- ThrowHelper.ThrowStartIndexArgumentOutOfRange_ArgumentOutOfRange_Index();
- }
- }
- else
- {
- // Make sure we're not out of range
- if (startIndex < 0 || startIndex >= array.Length)
- {
- ThrowHelper.ThrowStartIndexArgumentOutOfRange_ArgumentOutOfRange_Index();
- }
- }
- // 2nd have of this also catches when startIndex == MAXINT, so MAXINT - 0 + 1 == -1, which is < 0.
- if (count < 0 || startIndex - count + 1 < 0)
- {
- ThrowHelper.ThrowCountArgumentOutOfRange_ArgumentOutOfRange_Count();
- }
- int endIndex = startIndex - count;
- for (int i = startIndex; i > endIndex; i--)
- {
- if (match(array[i]))
- {
- return i;
- }
- }
- return -1;
- }
- public static void ForEach<T>(T[] array, Action<T> action)
- {
- if (array == null)
- {
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
- }
- if (action == null)
- {
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.action);
- }
- for (int i = 0; i < array.Length; i++)
- {
- action(array[i]);
- }
- }
- // GetEnumerator returns an IEnumerator over this Array.
- //
- // Currently, only one dimensional arrays are supported.
- //
- public IEnumerator GetEnumerator()
- {
- int lowerBound = GetLowerBound(0);
- if (Rank == 1 && lowerBound == 0)
- return new SZArrayEnumerator(this);
- else
- return new ArrayEnumerator(this, lowerBound, Length);
- }
- // Returns the index of the first occurrence of a given value in an array.
- // The array is searched forwards, and the elements of the array are
- // compared to the given value using the Object.Equals method.
- //
- public static int IndexOf(Array array, object value)
- {
- if (array == null)
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
- return IndexOf(array, value, array.GetLowerBound(0), array.Length);
- }
- // Returns the index of the first occurrence of a given value in a range of
- // an array. The array is searched forwards, starting at index
- // startIndex and ending at the last element of the array. The
- // elements of the array are compared to the given value using the
- // Object.Equals method.
- //
- public static int IndexOf(Array array, object value, int startIndex)
- {
- if (array == null)
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
- int lb = array.GetLowerBound(0);
- return IndexOf(array, value, startIndex, array.Length - startIndex + lb);
- }
- // Returns the index of the first occurrence of a given value in a range of
- // an array. The array is searched forwards, starting at index
- // startIndex and upto count elements. The
- // elements of the array are compared to the given value using the
- // Object.Equals method.
- //
- public static int IndexOf(Array array, object value, int startIndex, int count)
- {
- if (array == null)
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
- if (array.Rank != 1)
- ThrowHelper.ThrowRankException(ExceptionResource.Rank_MultiDimNotSupported);
- int lb = array.GetLowerBound(0);
- if (startIndex < lb || startIndex > array.Length + lb)
- ThrowHelper.ThrowStartIndexArgumentOutOfRange_ArgumentOutOfRange_Index();
- if (count < 0 || count > array.Length - startIndex + lb)
- ThrowHelper.ThrowCountArgumentOutOfRange_ArgumentOutOfRange_Count();
- #if CORECLR
- // Try calling a quick native method to handle primitive types.
- int retVal;
- bool r = TrySZIndexOf(array, startIndex, count, value, out retVal);
- if (r)
- return retVal;
- #endif
- object[] objArray = array as object[];
- int endIndex = startIndex + count;
- if (objArray != null)
- {
- if (value == null)
- {
- for (int i = startIndex; i < endIndex; i++)
- {
- if (objArray[i] == null) return i;
- }
- }
- else
- {
- for (int i = startIndex; i < endIndex; i++)
- {
- object obj = objArray[i];
- if (obj != null && obj.Equals(value)) return i;
- }
- }
- }
- else
- {
- for (int i = startIndex; i < endIndex; i++)
- {
- object obj = array.GetValue(i);
- if (obj == null)
- {
- if (value == null) return i;
- }
- else
- {
- if (obj.Equals(value)) return i;
- }
- }
- }
- // Return one less than the lower bound of the array. This way,
- // for arrays with a lower bound of -1 we will not return -1 when the
- // item was not found. And for SZArrays (the vast majority), -1 still
- // works for them.
- return lb - 1;
- }
- public static int IndexOf<T>(T[] array, T value)
- {
- if (array == null)
- {
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
- }
- return IndexOf(array, value, 0, array.Length);
- }
- public static int IndexOf<T>(T[] array, T value, int startIndex)
- {
- if (array == null)
- {
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
- }
- return IndexOf(array, value, startIndex, array.Length - startIndex);
- }
- public static int IndexOf<T>(T[] array, T value, int startIndex, int count)
- {
- if (array == null)
- {
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
- }
- if ((uint)startIndex > (uint)array.Length)
- {
- ThrowHelper.ThrowStartIndexArgumentOutOfRange_ArgumentOutOfRange_Index();
- }
- if ((uint)count > (uint)(array.Length - startIndex))
- {
- ThrowHelper.ThrowCountArgumentOutOfRange_ArgumentOutOfRange_Count();
- }
- if (typeof(T) == typeof(byte))
- {
- int result = SpanHelpers.IndexOf(
- ref Unsafe.Add(ref array.GetRawSzArrayData(), startIndex),
- Unsafe.As<T, byte>(ref value),
- count);
- return (result >= 0 ? startIndex : 0) + result;
- }
- if (typeof(T) == typeof(char))
- {
- int result = SpanHelpers.IndexOf(
- ref Unsafe.Add(ref Unsafe.As<byte, char>(ref array.GetRawSzArrayData()), startIndex),
- Unsafe.As<T, char>(ref value),
- count);
- return (result >= 0 ? startIndex : 0) + result;
- }
- #if CORECLR
- return EqualityComparer<T>.Default.IndexOf(array, value, startIndex, count);
- #else
- return IndexOfImpl(array, value, startIndex, count);
- #endif
- }
- // Returns the index of the last occurrence of a given value in an array.
- // The array is searched backwards, and the elements of the array are
- // compared to the given value using the Object.Equals method.
- //
- public static int LastIndexOf(Array array, object value)
- {
- if (array == null)
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
- int lb = array.GetLowerBound(0);
- return LastIndexOf(array, value, array.Length - 1 + lb, array.Length);
- }
- // Returns the index of the last occurrence of a given value in a range of
- // an array. The array is searched backwards, starting at index
- // startIndex and ending at index 0. The elements of the array are
- // compared to the given value using the Object.Equals method.
- //
- public static int LastIndexOf(Array array, object value, int startIndex)
- {
- if (array == null)
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
- int lb = array.GetLowerBound(0);
- return LastIndexOf(array, value, startIndex, startIndex + 1 - lb);
- }
- // Returns the index of the last occurrence of a given value in a range of
- // an array. The array is searched backwards, starting at index
- // startIndex and counting uptocount elements. The elements of
- // the array are compared to the given value using the Object.Equals
- // method.
- //
- public static int LastIndexOf(Array array, object value, int startIndex, int count)
- {
- if (array == null)
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
- int lb = array.GetLowerBound(0);
- if (array.Length == 0)
- {
- return lb - 1;
- }
- if (startIndex < lb || startIndex >= array.Length + lb)
- ThrowHelper.ThrowStartIndexArgumentOutOfRange_ArgumentOutOfRange_Index();
- if (count < 0)
- ThrowHelper.ThrowCountArgumentOutOfRange_ArgumentOutOfRange_Count();
- if (count > startIndex - lb + 1)
- ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.endIndex, ExceptionResource.ArgumentOutOfRange_EndIndexStartIndex);
- if (array.Rank != 1)
- ThrowHelper.ThrowRankException(ExceptionResource.Rank_MultiDimNotSupported);
- #if CORECLR
- // Try calling a quick native method to handle primitive types.
- int retVal;
- bool r = TrySZLastIndexOf(array, startIndex, count, value, out retVal);
- if (r)
- return retVal;
- #endif
- object[] objArray = array as object[];
- int endIndex = startIndex - count + 1;
- if (objArray != null)
- {
- if (value == null)
- {
- for (int i = startIndex; i >= endIndex; i--)
- {
- if (objArray[i] == null) return i;
- }
- }
- else
- {
- for (int i = startIndex; i >= endIndex; i--)
- {
- object obj = objArray[i];
- if (obj != null && obj.Equals(value)) return i;
- }
- }
- }
- else
- {
- for (int i = startIndex; i >= endIndex; i--)
- {
- object obj = array.GetValue(i);
- if (obj == null)
- {
- if (value == null) return i;
- }
- else
- {
- if (obj.Equals(value)) return i;
- }
- }
- }
- return lb - 1; // Return lb-1 for arrays with negative lower bounds.
- }
- public static int LastIndexOf<T>(T[] array, T value)
- {
- if (array == null)
- {
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
- }
- return LastIndexOf(array, value, array.Length - 1, array.Length);
- }
- public static int LastIndexOf<T>(T[] array, T value, int startIndex)
- {
- if (array == null)
- {
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
- }
- // if array is empty and startIndex is 0, we need to pass 0 as count
- return LastIndexOf(array, value, startIndex, (array.Length == 0) ? 0 : (startIndex + 1));
- }
- public static int LastIndexOf<T>(T[] array, T value, int startIndex, int count)
- {
- if (array == null)
- {
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
- }
- if (array.Length == 0)
- {
- //
- // Special case for 0 length List
- // accept -1 and 0 as valid startIndex for compablility reason.
- //
- if (startIndex != -1 && startIndex != 0)
- {
- ThrowHelper.ThrowStartIndexArgumentOutOfRange_ArgumentOutOfRange_Index();
- }
- // only 0 is a valid value for count if array is empty
- if (count != 0)
- {
- ThrowHelper.ThrowCountArgumentOutOfRange_ArgumentOutOfRange_Count();
- }
- return -1;
- }
- // Make sure we're not out of range
- if ((uint)startIndex >= (uint)array.Length)
- {
- ThrowHelper.ThrowStartIndexArgumentOutOfRange_ArgumentOutOfRange_Index();
- }
- // 2nd have of this also catches when startIndex == MAXINT, so MAXINT - 0 + 1 == -1, which is < 0.
- if (count < 0 || startIndex - count + 1 < 0)
- {
- ThrowHelper.ThrowCountArgumentOutOfRange_ArgumentOutOfRange_Count();
- }
- if (typeof(T) == typeof(byte))
- {
- int endIndex = startIndex - count + 1;
- int result = SpanHelpers.LastIndexOf(
- ref Unsafe.Add(ref array.GetRawSzArrayData(), endIndex),
- Unsafe.As<T, byte>(ref value),
- count);
- return (result >= 0 ? endIndex : 0) + result;
- }
- if (typeof(T) == typeof(char))
- {
- int endIndex = startIndex - count + 1;
- int result = SpanHelpers.LastIndexOf(
- ref Unsafe.Add(ref Unsafe.As<byte, char>(ref array.GetRawSzArrayData()), endIndex),
- Unsafe.As<T, char>(ref value),
- count);
- return (result >= 0 ? endIndex : 0) + result;
- }
- #if CORECLR
- return EqualityComparer<T>.Default.LastIndexOf(array, value, startIndex, count);
- #else
- return LastIndexOfImpl(array, value, startIndex, count);
- #endif
- }
- // Reverses all elements of the given array. Following a call to this
- // method, an element previously located at index i will now be
- // located at index length - i - 1, where length is the
- // length of the array.
- //
- public static void Reverse(Array array)
- {
- if (array == null)
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
- Reverse(array, array.GetLowerBound(0), array.Length);
- }
- // Reverses the elements in a range of an array. Following a call to this
- // method, an element in the range given by index and count
- // which was previously located at index i will now be located at
- // index index + (index + count - i - 1).
- // Reliability note: This may fail because it may have to box objects.
- //
- public static void Reverse(Array array, int index, int length)
- {
- if (array == null)
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
- int lowerBound = array.GetLowerBound(0);
- if (index < lowerBound)
- ThrowHelper.ThrowIndexArgumentOutOfRange_NeedNonNegNumException();
- if (length < 0)
- ThrowHelper.ThrowLengthArgumentOutOfRange_ArgumentOutOfRange_NeedNonNegNum();
- if (array.Length - (index - lowerBound) < length)
- ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidOffLen);
- if (array.Rank != 1)
- ThrowHelper.ThrowRankException(ExceptionResource.Rank_MultiDimNotSupported);
- if (length <= 1)
- return;
- #if CORECLR
- bool r = TrySZReverse(array, index, length);
- if (r)
- return;
- #endif
- if (array is object[] objArray)
- {
- Array.Reverse<object>(objArray, index, length);
- }
- else
- {
- int i = index;
- int j = index + length - 1;
- while (i < j)
- {
- object temp = array.GetValue(i);
- array.SetValue(array.GetValue(j), i);
- array.SetValue(temp, j);
- i++;
- j--;
- }
- }
- }
- public static void Reverse<T>(T[] array)
- {
- if (array == null)
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
- Reverse(array, 0, array.Length);
- }
-
- public static void Reverse<T>(T[] array, int index, int length)
- {
- if (array == null)
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
- if (index < 0)
- ThrowHelper.ThrowIndexArgumentOutOfRange_NeedNonNegNumException();
- if (length < 0)
- ThrowHelper.ThrowLengthArgumentOutOfRange_ArgumentOutOfRange_NeedNonNegNum();
- if (array.Length - index < length)
- ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidOffLen);
- if (length <= 1)
- return;
- ref T first = ref Unsafe.Add(ref Unsafe.As<byte, T>(ref array.GetRawSzArrayData()), index);
- ref T last = ref Unsafe.Add(ref Unsafe.Add(ref first, 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));
- }
- // Sorts the elements of an array. The sort compares the elements to each
- // other using the IComparable interface, which must be implemented
- // by all elements of the array.
- //
- public static void Sort(Array array)
- {
- if (array == null)
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
- Sort(array, null, array.GetLowerBound(0), array.Length, null);
- }
- // Sorts the elements of two arrays based on the keys in the first array.
- // Elements in the keys array specify the sort keys for
- // corresponding elements in the items array. The sort compares the
- // keys to each other using the IComparable interface, which must be
- // implemented by all elements of the keys array.
- //
- public static void Sort(Array keys, Array items)
- {
- if (keys == null)
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.keys);
- Sort(keys, items, keys.GetLowerBound(0), keys.Length, null);
- }
- // Sorts the elements in a section of an array. The sort compares the
- // elements to each other using the IComparable interface, which
- // must be implemented by all elements in the given section of the array.
- //
- public static void Sort(Array array, int index, int length)
- {
- Sort(array, null, index, length, null);
- }
- // Sorts the elements in a section of two arrays based on the keys in the
- // first array. Elements in the keys array specify the sort keys for
- // corresponding elements in the items array. The sort compares the
- // keys to each other using the IComparable interface, which must be
- // implemented by all elements of the keys array.
- //
- public static void Sort(Array keys, Array items, int index, int length)
- {
- Sort(keys, items, index, length, null);
- }
- // Sorts the elements of an array. The sort compares the elements to each
- // other using the given IComparer interface. If comparer is
- // null, the elements are compared to each other using the
- // IComparable interface, which in that case must be implemented by
- // all elements of the array.
- //
- public static void Sort(Array array, IComparer comparer)
- {
- if (array == null)
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
- Sort(array, null, array.GetLowerBound(0), array.Length, comparer);
- }
- // Sorts the elements of two arrays based on the keys in the first array.
- // Elements in the keys array specify the sort keys for
- // corresponding elements in the items array. The sort compares the
- // keys to each other using the given IComparer interface. If
- // comparer is null, the elements are compared to each other using
- // the IComparable interface, which in that case must be implemented
- // by all elements of the keys array.
- //
- public static void Sort(Array keys, Array items, IComparer comparer)
- {
- if (keys == null)
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.keys);
- Sort(keys, items, keys.GetLowerBound(0), keys.Length, comparer);
- }
- // Sorts the elements in a section of an array. The sort compares the
- // elements to each other using the given IComparer interface. If
- // comparer is null, the elements are compared to each other using
- // the IComparable interface, which in that case must be implemented
- // by all elements in the given section of the array.
- //
- public static void Sort(Array array, int index, int length, IComparer comparer)
- {
- Sort(array, null, index, length, comparer);
- }
- // Sorts the elements in a section of two arrays based on the keys in the
- // first array. Elements in the keys array specify the sort keys for
- // corresponding elements in the items array. The sort compares the
- // keys to each other using the given IComparer interface. If
- // comparer is null, the elements are compared to each other using
- // the IComparable interface, which in that case must be implemented
- // by all elements of the given section of the keys array.
- //
- public static void Sort(Array keys, Array items, int index, int length, IComparer comparer)
- {
- if (keys == null)
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.keys);
- if (keys.Rank != 1 || (items != null && items.Rank != 1))
- ThrowHelper.ThrowRankException(ExceptionResource.Rank_MultiDimNotSupported);
- int keysLowerBound = keys.GetLowerBound(0);
- if (items != null && keysLowerBound != items.GetLowerBound(0))
- ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_LowerBoundsMustMatch);
- if (index < keysLowerBound)
- ThrowHelper.ThrowIndexArgumentOutOfRange_NeedNonNegNumException();
- if (length < 0)
- ThrowHelper.ThrowLengthArgumentOutOfRange_ArgumentOutOfRange_NeedNonNegNum();
- if (keys.Length - (index - keysLowerBound) < length || (items != null && (index - keysLowerBound) > items.Length - length))
- ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidOffLen);
- if (length > 1)
- {
- SortImpl(keys, items, index, length, comparer ?? Comparer.Default);
- }
- }
- public static void Sort<T>(T[] array)
- {
- if (array == null)
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
- Sort<T>(array, 0, array.Length, null);
- }
- public static void Sort<TKey, TValue>(TKey[] keys, TValue[] items)
- {
- if (keys == null)
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.keys);
- Sort<TKey, TValue>(keys, items, 0, keys.Length, null);
- }
- public static void Sort<T>(T[] array, int index, int length)
- {
- Sort<T>(array, index, length, null);
- }
- public static void Sort<TKey, TValue>(TKey[] keys, TValue[] items, int index, int length)
- {
- Sort<TKey, TValue>(keys, items, index, length, null);
- }
- public static void Sort<T>(T[] array, System.Collections.Generic.IComparer<T> comparer)
- {
- if (array == null)
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
- Sort<T>(array, 0, array.Length, comparer);
- }
- public static void Sort<TKey, TValue>(TKey[] keys, TValue[] items, System.Collections.Generic.IComparer<TKey> comparer)
- {
- if (keys == null)
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.keys);
- Sort<TKey, TValue>(keys, items, 0, keys.Length, comparer);
- }
- public static void Sort<T>(T[] array, int index, int length, System.Collections.Generic.IComparer<T> comparer)
- {
- if (array == null)
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
- if (index < 0)
- ThrowHelper.ThrowIndexArgumentOutOfRange_NeedNonNegNumException();
- if (length < 0)
- ThrowHelper.ThrowLengthArgumentOutOfRange_ArgumentOutOfRange_NeedNonNegNum();
- if (array.Length - index < length)
- ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidOffLen);
- if (length > 1)
- {
- #if CORECLR
- if (comparer == null || comparer == Comparer<T>.Default)
- {
- if (TrySZSort(array, null, index, index + length - 1))
- {
- return;
- }
- }
- #endif
- ArraySortHelper<T>.Default.Sort(array, index, length, comparer);
- }
- }
- public static void Sort<TKey, TValue>(TKey[] keys, TValue[] items, int index, int length, System.Collections.Generic.IComparer<TKey> comparer)
- {
- if (keys == null)
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.keys);
- if (index < 0)
- ThrowHelper.ThrowIndexArgumentOutOfRange_NeedNonNegNumException();
- if (length < 0)
- ThrowHelper.ThrowLengthArgumentOutOfRange_ArgumentOutOfRange_NeedNonNegNum();
- if (keys.Length - index < length || (items != null && index > items.Length - length))
- ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidOffLen);
- if (length > 1)
- {
- #if CORECLR
- if (comparer == null || comparer == Comparer<TKey>.Default)
- {
- if (TrySZSort(keys, items, index, index + length - 1))
- {
- return;
- }
- }
- #endif
- if (items == null)
- {
- Sort<TKey>(keys, index, length, comparer);
- return;
- }
- ArraySortHelper<TKey, TValue>.Default.Sort(keys, items, index, length, comparer);
- }
- }
- public static void Sort<T>(T[] array, Comparison<T> comparison)
- {
- if (array == null)
- {
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
- }
- if (comparison == null)
- {
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.comparison);
- }
- ArraySortHelper<T>.Sort(array, 0, array.Length, comparison);
- }
- public static bool TrueForAll<T>(T[] array, Predicate<T> match)
- {
- if (array == null)
- {
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
- }
- if (match == null)
- {
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match);
- }
- for (int i = 0; i < array.Length; i++)
- {
- if (!match(array[i]))
- {
- return false;
- }
- }
- return true;
- }
- // Private value type used by the Sort methods.
- private readonly struct SorterObjectArray
- {
- private readonly object[] keys;
- private readonly object[] items;
- private readonly IComparer comparer;
- internal SorterObjectArray(object[] keys, object[] items, IComparer comparer)
- {
- this.keys = keys;
- this.items = items;
- this.comparer = comparer;
- }
- internal void SwapIfGreaterWithItems(int a, int b)
- {
- if (a != b)
- {
- if (comparer.Compare(keys[a], keys[b]) > 0)
- {
- object temp = keys[a];
- keys[a] = keys[b];
- keys[b] = temp;
- if (items != null)
- {
- object item = items[a];
- items[a] = items[b];
- items[b] = item;
- }
- }
- }
- }
- private void Swap(int i, int j)
- {
- object t = keys[i];
- keys[i] = keys[j];
- keys[j] = t;
- if (items != null)
- {
- object item = items[i];
- items[i] = items[j];
- items[j] = item;
- }
- }
- internal void Sort(int left, int length)
- {
- IntrospectiveSort(left, length);
- }
- private void IntrospectiveSort(int left, int length)
- {
- if (length < 2)
- return;
- try
- {
- IntroSort(left, length + left - 1, 2 * IntrospectiveSortUtilities.FloorLog2PlusOne(length));
- }
- catch (IndexOutOfRangeException)
- {
- IntrospectiveSortUtilities.ThrowOrIgnoreBadComparer(comparer);
- }
- catch (Exception e)
- {
- ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_IComparerFailed, e);
- }
- }
- private void IntroSort(int lo, int hi, int depthLimit)
- {
- while (hi > lo)
- {
- int partitionSize = hi - lo + 1;
- if (partitionSize <= IntrospectiveSortUtilities.IntrosortSizeThreshold)
- {
- if (partitionSize == 1)
- {
- return;
- }
- if (partitionSize == 2)
- {
- SwapIfGreaterWithItems(lo, hi);
- return;
- }
- if (partitionSize == 3)
- {
- SwapIfGreaterWithItems(lo, hi - 1);
- SwapIfGreaterWithItems(lo, hi);
- SwapIfGreaterWithItems(hi - 1, hi);
- return;
- }
- InsertionSort(lo, hi);
- return;
- }
- if (depthLimit == 0)
- {
- Heapsort(lo, hi);
- return;
- }
- depthLimit--;
- int p = PickPivotAndPartition(lo, hi);
- IntroSort(p + 1, hi, depthLimit);
- hi = p - 1;
- }
- }
- private int PickPivotAndPartition(int lo, int hi)
- {
- // Compute median-of-three. But also partition them, since we've done the comparison.
- int mid = lo + (hi - lo) / 2;
- // Sort lo, mid and hi appropriately, then pick mid as the pivot.
- SwapIfGreaterWithItems(lo, mid);
- SwapIfGreaterWithItems(lo, hi);
- SwapIfGreaterWithItems(mid, hi);
- object pivot = keys[mid];
- Swap(mid, hi - 1);
- int left = lo, right = hi - 1; // We already partitioned lo and hi and put the pivot in hi - 1. And we pre-increment & decrement below.
- while (left < right)
- {
- while (comparer.Compare(keys[++left], pivot) < 0) ;
- while (comparer.Compare(pivot, keys[--right]) < 0) ;
- if (left >= right)
- break;
- Swap(left, right);
- }
- // Put pivot in the right location.
- Swap(left, (hi - 1));
- return left;
- }
- private void Heapsort(int lo, int hi)
- {
- int n = hi - lo + 1;
- for (int i = n / 2; i >= 1; i = i - 1)
- {
- DownHeap(i, n, lo);
- }
- for (int i = n; i > 1; i = i - 1)
- {
- Swap(lo, lo + i - 1);
- DownHeap(1, i - 1, lo);
- }
- }
- private void DownHeap(int i, int n, int lo)
- {
- object d = keys[lo + i - 1];
- object dt = (items != null) ? items[lo + i - 1] : null;
- int child;
- while (i <= n / 2)
- {
- child = 2 * i;
- if (child < n && comparer.Compare(keys[lo + child - 1], keys[lo + child]) < 0)
- {
- child++;
- }
- if (!(comparer.Compare(d, keys[lo + child - 1]) < 0))
- break;
- keys[lo + i - 1] = keys[lo + child - 1];
- if (items != null)
- items[lo + i - 1] = items[lo + child - 1];
- i = child;
- }
- keys[lo + i - 1] = d;
- if (items != null)
- items[lo + i - 1] = dt;
- }
- private void InsertionSort(int lo, int hi)
- {
- int i, j;
- object t, ti;
- for (i = lo; i < hi; i++)
- {
- j = i;
- t = keys[i + 1];
- ti = (items != null) ? items[i + 1] : null;
- while (j >= lo && comparer.Compare(t, keys[j]) < 0)
- {
- keys[j + 1] = keys[j];
- if (items != null)
- items[j + 1] = items[j];
- j--;
- }
- keys[j + 1] = t;
- if (items != null)
- items[j + 1] = ti;
- }
- }
- }
- // Private value used by the Sort methods for instances of Array.
- // This is slower than the one for Object[], since we can't use the JIT helpers
- // to access the elements. We must use GetValue & SetValue.
- private readonly struct SorterGenericArray
- {
- private readonly Array keys;
- private readonly Array items;
- private readonly IComparer comparer;
- internal SorterGenericArray(Array keys, Array items, IComparer comparer)
- {
- this.keys = keys;
- this.items = items;
- this.comparer = comparer;
- }
- internal void SwapIfGreaterWithItems(int a, int b)
- {
- if (a != b)
- {
- if (comparer.Compare(keys.GetValue(a), keys.GetValue(b)) > 0)
- {
- object key = keys.GetValue(a);
- keys.SetValue(keys.GetValue(b), a);
- keys.SetValue(key, b);
- if (items != null)
- {
- object item = items.GetValue(a);
- items.SetValue(items.GetValue(b), a);
- items.SetValue(item, b);
- }
- }
- }
- }
- private void Swap(int i, int j)
- {
- object t1 = keys.GetValue(i);
- keys.SetValue(keys.GetValue(j), i);
- keys.SetValue(t1, j);
- if (items != null)
- {
- object t2 = items.GetValue(i);
- items.SetValue(items.GetValue(j), i);
- items.SetValue(t2, j);
- }
- }
- internal void Sort(int left, int length)
- {
- IntrospectiveSort(left, length);
- }
- private void IntrospectiveSort(int left, int length)
- {
- if (length < 2)
- return;
- try
- {
- IntroSort(left, length + left - 1, 2 * IntrospectiveSortUtilities.FloorLog2PlusOne(length));
- }
- catch (IndexOutOfRangeException)
- {
- IntrospectiveSortUtilities.ThrowOrIgnoreBadComparer(comparer);
- }
- catch (Exception e)
- {
- ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_IComparerFailed, e);
- }
- }
- private void IntroSort(int lo, int hi, int depthLimit)
- {
- while (hi > lo)
- {
- int partitionSize = hi - lo + 1;
- if (partitionSize <= IntrospectiveSortUtilities.IntrosortSizeThreshold)
- {
- if (partitionSize == 1)
- {
- return;
- }
- if (partitionSize == 2)
- {
- SwapIfGreaterWithItems(lo, hi);
- return;
- }
- if (partitionSize == 3)
- {
- SwapIfGreaterWithItems(lo, hi - 1);
- SwapIfGreaterWithItems(lo, hi);
- SwapIfGreaterWithItems(hi - 1, hi);
- return;
- }
- InsertionSort(lo, hi);
- return;
- }
- if (depthLimit == 0)
- {
- Heapsort(lo, hi);
- return;
- }
- depthLimit--;
- int p = PickPivotAndPartition(lo, hi);
- IntroSort(p + 1, hi, depthLimit);
- hi = p - 1;
- }
- }
- private int PickPivotAndPartition(int lo, int hi)
- {
- // Compute median-of-three. But also partition them, since we've done the comparison.
- int mid = lo + (hi - lo) / 2;
- SwapIfGreaterWithItems(lo, mid);
- SwapIfGreaterWithItems(lo, hi);
- SwapIfGreaterWithItems(mid, hi);
- object pivot = keys.GetValue(mid);
- Swap(mid, hi - 1);
- int left = lo, right = hi - 1; // We already partitioned lo and hi and put the pivot in hi - 1. And we pre-increment & decrement below.
- while (left < right)
- {
- while (comparer.Compare(keys.GetValue(++left), pivot) < 0) ;
- while (comparer.Compare(pivot, keys.GetValue(--right)) < 0) ;
- if (left >= right)
- break;
- Swap(left, right);
- }
- // Put pivot in the right location.
- Swap(left, (hi - 1));
- return left;
- }
- private void Heapsort(int lo, int hi)
- {
- int n = hi - lo + 1;
- for (int i = n / 2; i >= 1; i = i - 1)
- {
- DownHeap(i, n, lo);
- }
- for (int i = n; i > 1; i = i - 1)
- {
- Swap(lo, lo + i - 1);
- DownHeap(1, i - 1, lo);
- }
- }
- private void DownHeap(int i, int n, int lo)
- {
- object d = keys.GetValue(lo + i - 1);
- object dt = (items != null) ? items.GetValue(lo + i - 1) : null;
- int child;
- while (i <= n / 2)
- {
- child = 2 * i;
- if (child < n && comparer.Compare(keys.GetValue(lo + child - 1), keys.GetValue(lo + child)) < 0)
- {
- child++;
- }
- if (!(comparer.Compare(d, keys.GetValue(lo + child - 1)) < 0))
- break;
- keys.SetValue(keys.GetValue(lo + child - 1), lo + i - 1);
- if (items != null)
- items.SetValue(items.GetValue(lo + child - 1), lo + i - 1);
- i = child;
- }
- keys.SetValue(d, lo + i - 1);
- if (items != null)
- items.SetValue(dt, lo + i - 1);
- }
- private void InsertionSort(int lo, int hi)
- {
- int i, j;
- object t, dt;
- for (i = lo; i < hi; i++)
- {
- j = i;
- t = keys.GetValue(i + 1);
- dt = (items != null) ? items.GetValue(i + 1) : null;
- while (j >= lo && comparer.Compare(t, keys.GetValue(j)) < 0)
- {
- keys.SetValue(keys.GetValue(j), j + 1);
- if (items != null)
- items.SetValue(items.GetValue(j), j + 1);
- j--;
- }
- keys.SetValue(t, j + 1);
- if (items != null)
- items.SetValue(dt, j + 1);
- }
- }
- }
- private sealed class SZArrayEnumerator : IEnumerator, ICloneable
- {
- private readonly Array _array;
- private int _index;
- private int _endIndex; // Cache Array.Length, since it's a little slow.
- internal SZArrayEnumerator(Array array)
- {
- Debug.Assert(array.Rank == 1 && array.GetLowerBound(0) == 0, "SZArrayEnumerator only works on single dimension arrays w/ a lower bound of zero.");
- _array = array;
- _index = -1;
- _endIndex = array.Length;
- }
- public object Clone()
- {
- return MemberwiseClone();
- }
- public bool MoveNext()
- {
- if (_index < _endIndex)
- {
- _index++;
- return (_index < _endIndex);
- }
- return false;
- }
- public object Current
- {
- get
- {
- if (_index < 0) ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumNotStarted();
- if (_index >= _endIndex) ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumEnded();
- return _array.GetValue(_index);
- }
- }
- public void Reset()
- {
- _index = -1;
- }
- }
- private sealed class ArrayEnumerator : IEnumerator, ICloneable
- {
- private Array array;
- private int index;
- private int endIndex;
- private int startIndex; // Save for Reset.
- private int[] _indices; // The current position in a multidim array
- private bool _complete;
- internal ArrayEnumerator(Array array, int index, int count)
- {
- this.array = array;
- this.index = index - 1;
- startIndex = index;
- endIndex = index + count;
- _indices = new int[array.Rank];
- int checkForZero = 1; // Check for dimensions of size 0.
- for (int i = 0; i < array.Rank; i++)
- {
- _indices[i] = array.GetLowerBound(i);
- checkForZero *= array.GetLength(i);
- }
- // To make MoveNext simpler, decrement least significant index.
- _indices[_indices.Length - 1]--;
- _complete = (checkForZero == 0);
- }
- private void IncArray()
- {
- // This method advances us to the next valid array index,
- // handling all the multiple dimension & bounds correctly.
- // Think of it like an odometer in your car - we start with
- // the last digit, increment it, and check for rollover. If
- // it rolls over, we set all digits to the right and including
- // the current to the appropriate lower bound. Do these overflow
- // checks for each dimension, and if the most significant digit
- // has rolled over it's upper bound, we're done.
- //
- int rank = array.Rank;
- _indices[rank - 1]++;
- for (int dim = rank - 1; dim >= 0; dim--)
- {
- if (_indices[dim] > array.GetUpperBound(dim))
- {
- if (dim == 0)
- {
- _complete = true;
- break;
- }
- for (int j = dim; j < rank; j++)
- _indices[j] = array.GetLowerBound(j);
- _indices[dim - 1]++;
- }
- }
- }
- public object Clone()
- {
- return MemberwiseClone();
- }
- public bool MoveNext()
- {
- if (_complete)
- {
- index = endIndex;
- return false;
- }
- index++;
- IncArray();
- return !_complete;
- }
- public object Current
- {
- get
- {
- if (index < startIndex) ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumNotStarted();
- if (_complete) ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumEnded();
- return array.GetValue(_indices);
- }
- }
- public void Reset()
- {
- index = startIndex - 1;
- int checkForZero = 1;
- for (int i = 0; i < array.Rank; i++)
- {
- _indices[i] = array.GetLowerBound(i);
- checkForZero *= array.GetLength(i);
- }
- _complete = (checkForZero == 0);
- // To make MoveNext simpler, decrement least significant index.
- _indices[_indices.Length - 1]--;
- }
- }
- }
- }
|