| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012 |
- // 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);
- return BinarySearch(array, array.GetLowerBound(0), 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]);
- }
- }
- // 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();
- }
- // Hits a code generation bug on ProjectN
- #if !PROJECTN
- 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;
- }
- #endif
- #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();
- }
- // Hits a code generation bug on ProjectN
- #if !PROJECTN
- 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;
- }
- #endif
- #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;
- }
- #if !CORERT
- // 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);
- }
- }
- }
- public IEnumerator GetEnumerator()
- {
- int lowerBound = GetLowerBound(0);
- if (Rank == 1 && lowerBound == 0)
- return new SZArrayEnumerator(this);
- else
- return new ArrayEnumerator(this, lowerBound, Length);
- }
- #endif // !CORERT
- }
- }
|