| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152 |
- // 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();
- }
- 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;
- }
- #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);
- }
- 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]--;
- }
- }
- #endif // !CORERT
- }
- }
|