Array.cs 76 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047
  1. // Licensed to the .NET Foundation under one or more agreements.
  2. // The .NET Foundation licenses this file to you under the MIT license.
  3. // See the LICENSE file in the project root for more information.
  4. using System.Collections;
  5. using System.Collections.Generic;
  6. using System.Collections.ObjectModel;
  7. using System.Diagnostics;
  8. using System.Diagnostics.CodeAnalysis;
  9. using System.Runtime.CompilerServices;
  10. using System.Runtime.InteropServices;
  11. using Internal.Runtime.CompilerServices;
  12. namespace System
  13. {
  14. [Serializable]
  15. [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
  16. public abstract partial class Array : ICloneable, IList, IStructuralComparable, IStructuralEquatable
  17. {
  18. // We impose limits on maximum array lenght in each dimension to allow efficient
  19. // implementation of advanced range check elimination in future.
  20. // Keep in sync with vm\gcscan.cpp and HashHelpers.MaxPrimeArrayLength.
  21. // The constants are defined in this method: inline SIZE_T MaxArrayLength(SIZE_T componentSize) from gcscan
  22. // We have different max sizes for arrays with elements of size 1 for backwards compatibility
  23. internal const int MaxArrayLength = 0X7FEFFFFF;
  24. internal const int MaxByteArrayLength = 0x7FFFFFC7;
  25. // This ctor exists solely to prevent C# from generating a protected .ctor that violates the surface area. I really want this to be a
  26. // "protected-and-internal" rather than "internal" but C# has no keyword for the former.
  27. internal Array() { }
  28. public static ReadOnlyCollection<T> AsReadOnly<T>(T[] array)
  29. {
  30. if (array == null)
  31. {
  32. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
  33. }
  34. // T[] implements IList<T>.
  35. return new ReadOnlyCollection<T>(array);
  36. }
  37. public static void Resize<T>([NotNull] ref T[]? array, int newSize)
  38. {
  39. if (newSize < 0)
  40. ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.newSize, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum);
  41. T[]? larray = array;
  42. if (larray == null)
  43. {
  44. array = new T[newSize];
  45. return;
  46. }
  47. if (larray.Length != newSize)
  48. {
  49. T[] newArray = new T[newSize];
  50. Copy(larray, 0, newArray, 0, larray.Length > newSize ? newSize : larray.Length);
  51. array = newArray;
  52. }
  53. }
  54. public static Array CreateInstance(Type elementType, params long[] lengths)
  55. {
  56. if (lengths == null)
  57. {
  58. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.lengths);
  59. }
  60. if (lengths.Length == 0)
  61. ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_NeedAtLeast1Rank);
  62. int[] intLengths = new int[lengths.Length];
  63. for (int i = 0; i < lengths.Length; ++i)
  64. {
  65. long len = lengths[i];
  66. int ilen = (int)len;
  67. if (len != ilen)
  68. ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.len, ExceptionResource.ArgumentOutOfRange_HugeArrayNotSupported);
  69. intLengths[i] = ilen;
  70. }
  71. return Array.CreateInstance(elementType, intLengths);
  72. }
  73. public static void Copy(Array sourceArray, Array destinationArray, long length)
  74. {
  75. int ilength = (int)length;
  76. if (length != ilength)
  77. ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.length, ExceptionResource.ArgumentOutOfRange_HugeArrayNotSupported);
  78. Copy(sourceArray, destinationArray, ilength);
  79. }
  80. public static void Copy(Array sourceArray, long sourceIndex, Array destinationArray, long destinationIndex, long length)
  81. {
  82. int isourceIndex = (int)sourceIndex;
  83. int idestinationIndex = (int)destinationIndex;
  84. int ilength = (int)length;
  85. if (sourceIndex != isourceIndex)
  86. ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.sourceIndex, ExceptionResource.ArgumentOutOfRange_HugeArrayNotSupported);
  87. if (destinationIndex != idestinationIndex)
  88. ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.destinationIndex, ExceptionResource.ArgumentOutOfRange_HugeArrayNotSupported);
  89. if (length != ilength)
  90. ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.length, ExceptionResource.ArgumentOutOfRange_HugeArrayNotSupported);
  91. Copy(sourceArray, isourceIndex, destinationArray, idestinationIndex, ilength);
  92. }
  93. public object? GetValue(long index)
  94. {
  95. int iindex = (int)index;
  96. if (index != iindex)
  97. ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index, ExceptionResource.ArgumentOutOfRange_HugeArrayNotSupported);
  98. return this.GetValue(iindex);
  99. }
  100. public object? GetValue(long index1, long index2)
  101. {
  102. int iindex1 = (int)index1;
  103. int iindex2 = (int)index2;
  104. if (index1 != iindex1)
  105. ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index1, ExceptionResource.ArgumentOutOfRange_HugeArrayNotSupported);
  106. if (index2 != iindex2)
  107. ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index2, ExceptionResource.ArgumentOutOfRange_HugeArrayNotSupported);
  108. return this.GetValue(iindex1, iindex2);
  109. }
  110. public object? GetValue(long index1, long index2, long index3)
  111. {
  112. int iindex1 = (int)index1;
  113. int iindex2 = (int)index2;
  114. int iindex3 = (int)index3;
  115. if (index1 != iindex1)
  116. ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index1, ExceptionResource.ArgumentOutOfRange_HugeArrayNotSupported);
  117. if (index2 != iindex2)
  118. ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index2, ExceptionResource.ArgumentOutOfRange_HugeArrayNotSupported);
  119. if (index3 != iindex3)
  120. ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index3, ExceptionResource.ArgumentOutOfRange_HugeArrayNotSupported);
  121. return this.GetValue(iindex1, iindex2, iindex3);
  122. }
  123. public object? GetValue(params long[] indices)
  124. {
  125. if (indices == null)
  126. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.indices);
  127. if (Rank != indices.Length)
  128. ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_RankIndices);
  129. int[] intIndices = new int[indices.Length];
  130. for (int i = 0; i < indices.Length; ++i)
  131. {
  132. long index = indices[i];
  133. int iindex = (int)index;
  134. if (index != iindex)
  135. ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index, ExceptionResource.ArgumentOutOfRange_HugeArrayNotSupported);
  136. intIndices[i] = iindex;
  137. }
  138. return this.GetValue(intIndices);
  139. }
  140. public void SetValue(object? value, long index)
  141. {
  142. int iindex = (int)index;
  143. if (index != iindex)
  144. ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index, ExceptionResource.ArgumentOutOfRange_HugeArrayNotSupported);
  145. this.SetValue(value, iindex);
  146. }
  147. public void SetValue(object? value, long index1, long index2)
  148. {
  149. int iindex1 = (int)index1;
  150. int iindex2 = (int)index2;
  151. if (index1 != iindex1)
  152. ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index1, ExceptionResource.ArgumentOutOfRange_HugeArrayNotSupported);
  153. if (index2 != iindex2)
  154. ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index2, ExceptionResource.ArgumentOutOfRange_HugeArrayNotSupported);
  155. this.SetValue(value, iindex1, iindex2);
  156. }
  157. public void SetValue(object? value, long index1, long index2, long index3)
  158. {
  159. int iindex1 = (int)index1;
  160. int iindex2 = (int)index2;
  161. int iindex3 = (int)index3;
  162. if (index1 != iindex1)
  163. ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index1, ExceptionResource.ArgumentOutOfRange_HugeArrayNotSupported);
  164. if (index2 != iindex2)
  165. ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index2, ExceptionResource.ArgumentOutOfRange_HugeArrayNotSupported);
  166. if (index3 != iindex3)
  167. ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index3, ExceptionResource.ArgumentOutOfRange_HugeArrayNotSupported);
  168. this.SetValue(value, iindex1, iindex2, iindex3);
  169. }
  170. public void SetValue(object? value, params long[] indices)
  171. {
  172. if (indices == null)
  173. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.indices);
  174. if (Rank != indices.Length)
  175. ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_RankIndices);
  176. int[] intIndices = new int[indices.Length];
  177. for (int i = 0; i < indices.Length; ++i)
  178. {
  179. long index = indices[i];
  180. int iindex = (int)index;
  181. if (index != iindex)
  182. ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index, ExceptionResource.ArgumentOutOfRange_HugeArrayNotSupported);
  183. intIndices[i] = iindex;
  184. }
  185. this.SetValue(value, intIndices);
  186. }
  187. private static int GetMedian(int low, int hi)
  188. {
  189. // Note both may be negative, if we are dealing with arrays w/ negative lower bounds.
  190. Debug.Assert(low <= hi);
  191. Debug.Assert(hi - low >= 0, "Length overflow!");
  192. return low + ((hi - low) >> 1);
  193. }
  194. public long GetLongLength(int dimension)
  195. {
  196. //This method should throw an IndexOufOfRangeException for compat if dimension < 0 or >= Rank
  197. return GetLength(dimension);
  198. }
  199. // Number of elements in the Array.
  200. int ICollection.Count { get { return Length; } }
  201. // Returns an object appropriate for synchronizing access to this
  202. // Array.
  203. public object SyncRoot { get { return this; } }
  204. // Is this Array read-only?
  205. public bool IsReadOnly { get { return false; } }
  206. public bool IsFixedSize { get { return true; } }
  207. // Is this Array synchronized (i.e., thread-safe)? If you want a synchronized
  208. // collection, you can use SyncRoot as an object to synchronize your
  209. // collection with. You could also call GetSynchronized()
  210. // to get a synchronized wrapper around the Array.
  211. public bool IsSynchronized { get { return false; } }
  212. object? IList.this[int index]
  213. {
  214. get { return GetValue(index); }
  215. set { SetValue(value, index); }
  216. }
  217. int IList.Add(object? value)
  218. {
  219. ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_FixedSizeCollection);
  220. return default;
  221. }
  222. bool IList.Contains(object? value)
  223. {
  224. return Array.IndexOf(this, value) >= this.GetLowerBound(0);
  225. }
  226. void IList.Clear()
  227. {
  228. Array.Clear(this, this.GetLowerBound(0), this.Length);
  229. }
  230. int IList.IndexOf(object? value)
  231. {
  232. return Array.IndexOf(this, value);
  233. }
  234. void IList.Insert(int index, object? value)
  235. {
  236. ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_FixedSizeCollection);
  237. }
  238. void IList.Remove(object? value)
  239. {
  240. ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_FixedSizeCollection);
  241. }
  242. void IList.RemoveAt(int index)
  243. {
  244. ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_FixedSizeCollection);
  245. }
  246. // Make a new array which is a shallow copy of the original array.
  247. //
  248. public object Clone()
  249. {
  250. return MemberwiseClone();
  251. }
  252. int IStructuralComparable.CompareTo(object? other, IComparer comparer)
  253. {
  254. if (other == null)
  255. {
  256. return 1;
  257. }
  258. Array? o = other as Array;
  259. if (o == null || this.Length != o.Length)
  260. {
  261. ThrowHelper.ThrowArgumentException(ExceptionResource.ArgumentException_OtherNotArrayOfCorrectLength, ExceptionArgument.other);
  262. }
  263. int i = 0;
  264. int c = 0;
  265. while (i < o.Length && c == 0)
  266. {
  267. object? left = GetValue(i);
  268. object? right = o.GetValue(i);
  269. c = comparer.Compare(left, right);
  270. i++;
  271. }
  272. return c;
  273. }
  274. bool IStructuralEquatable.Equals(object? other, IEqualityComparer comparer)
  275. {
  276. if (other == null)
  277. {
  278. return false;
  279. }
  280. if (object.ReferenceEquals(this, other))
  281. {
  282. return true;
  283. }
  284. if (!(other is Array o) || o.Length != this.Length)
  285. {
  286. return false;
  287. }
  288. int i = 0;
  289. while (i < o.Length)
  290. {
  291. object? left = GetValue(i);
  292. object? right = o.GetValue(i);
  293. if (!comparer.Equals(left, right))
  294. {
  295. return false;
  296. }
  297. i++;
  298. }
  299. return true;
  300. }
  301. private static int CombineHashCodes(int h1, int h2)
  302. {
  303. return (((h1 << 5) + h1) ^ h2);
  304. }
  305. int IStructuralEquatable.GetHashCode(IEqualityComparer comparer)
  306. {
  307. if (comparer == null)
  308. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.comparer);
  309. int ret = 0;
  310. for (int i = (this.Length >= 8 ? this.Length - 8 : 0); i < this.Length; i++)
  311. {
  312. ret = CombineHashCodes(ret, comparer.GetHashCode(GetValue(i)!));
  313. }
  314. return ret;
  315. }
  316. // Searches an array for a given element using a binary search algorithm.
  317. // Elements of the array are compared to the search value using the
  318. // IComparable interface, which must be implemented by all elements
  319. // of the array and the given search value. This method assumes that the
  320. // array is already sorted according to the IComparable interface;
  321. // if this is not the case, the result will be incorrect.
  322. //
  323. // The method returns the index of the given value in the array. If the
  324. // array does not contain the given value, the method returns a negative
  325. // integer. The bitwise complement operator (~) can be applied to a
  326. // negative result to produce the index of the first element (if any) that
  327. // is larger than the given search value.
  328. //
  329. public static int BinarySearch(Array array, object? value)
  330. {
  331. if (array == null)
  332. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
  333. return BinarySearch(array, array.GetLowerBound(0), array.Length, value, null);
  334. }
  335. // Searches a section of an array for a given element using a binary search
  336. // algorithm. Elements of the array are compared to the search value using
  337. // the IComparable interface, which must be implemented by all
  338. // elements of the array and the given search value. This method assumes
  339. // that the array is already sorted according to the IComparable
  340. // interface; if this is not the case, the result will be incorrect.
  341. //
  342. // The method returns the index of the given value in the array. If the
  343. // array does not contain the given value, the method returns a negative
  344. // integer. The bitwise complement operator (~) can be applied to a
  345. // negative result to produce the index of the first element (if any) that
  346. // is larger than the given search value.
  347. //
  348. public static int BinarySearch(Array array, int index, int length, object? value)
  349. {
  350. return BinarySearch(array, index, length, value, null);
  351. }
  352. // Searches an array for a given element using a binary search algorithm.
  353. // Elements of the array are compared to the search value using the given
  354. // IComparer interface. If comparer is null, elements of the
  355. // array are compared to the search value using the IComparable
  356. // interface, which in that case must be implemented by all elements of the
  357. // array and the given search value. This method assumes that the array is
  358. // already sorted; if this is not the case, the result will be incorrect.
  359. //
  360. // The method returns the index of the given value in the array. If the
  361. // array does not contain the given value, the method returns a negative
  362. // integer. The bitwise complement operator (~) can be applied to a
  363. // negative result to produce the index of the first element (if any) that
  364. // is larger than the given search value.
  365. //
  366. public static int BinarySearch(Array array, object? value, IComparer? comparer)
  367. {
  368. if (array == null)
  369. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
  370. return BinarySearch(array, array.GetLowerBound(0), array.Length, value, comparer);
  371. }
  372. // Searches a section of an array for a given element using a binary search
  373. // algorithm. Elements of the array are compared to the search value using
  374. // the given IComparer interface. If comparer is null,
  375. // elements of the array are compared to the search value using the
  376. // IComparable interface, which in that case must be implemented by
  377. // all elements of the array and the given search value. This method
  378. // assumes that the array is already sorted; if this is not the case, the
  379. // result will be incorrect.
  380. //
  381. // The method returns the index of the given value in the array. If the
  382. // array does not contain the given value, the method returns a negative
  383. // integer. The bitwise complement operator (~) can be applied to a
  384. // negative result to produce the index of the first element (if any) that
  385. // is larger than the given search value.
  386. //
  387. public static int BinarySearch(Array array, int index, int length, object? value, IComparer? comparer)
  388. {
  389. if (array == null)
  390. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
  391. int lb = array.GetLowerBound(0);
  392. if (index < lb)
  393. ThrowHelper.ThrowIndexArgumentOutOfRange_NeedNonNegNumException();
  394. if (length < 0)
  395. ThrowHelper.ThrowLengthArgumentOutOfRange_ArgumentOutOfRange_NeedNonNegNum();
  396. if (array.Length - (index - lb) < length)
  397. ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidOffLen);
  398. if (array.Rank != 1)
  399. ThrowHelper.ThrowRankException(ExceptionResource.Rank_MultiDimNotSupported);
  400. if (comparer == null) comparer = Comparer.Default;
  401. #if CORECLR
  402. if (comparer == Comparer.Default)
  403. {
  404. int retval;
  405. bool r = TrySZBinarySearch(array, index, length, value, out retval);
  406. if (r)
  407. return retval;
  408. }
  409. #endif
  410. int lo = index;
  411. int hi = index + length - 1;
  412. if (array is object[] objArray)
  413. {
  414. while (lo <= hi)
  415. {
  416. // i might overflow if lo and hi are both large positive numbers.
  417. int i = GetMedian(lo, hi);
  418. int c;
  419. try
  420. {
  421. c = comparer.Compare(objArray[i], value);
  422. }
  423. catch (Exception e)
  424. {
  425. ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_IComparerFailed, e);
  426. return default;
  427. }
  428. if (c == 0) return i;
  429. if (c < 0)
  430. {
  431. lo = i + 1;
  432. }
  433. else
  434. {
  435. hi = i - 1;
  436. }
  437. }
  438. }
  439. else
  440. {
  441. while (lo <= hi)
  442. {
  443. int i = GetMedian(lo, hi);
  444. int c;
  445. try
  446. {
  447. c = comparer.Compare(array.GetValue(i), value);
  448. }
  449. catch (Exception e)
  450. {
  451. ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_IComparerFailed, e);
  452. return default;
  453. }
  454. if (c == 0) return i;
  455. if (c < 0)
  456. {
  457. lo = i + 1;
  458. }
  459. else
  460. {
  461. hi = i - 1;
  462. }
  463. }
  464. }
  465. return ~lo;
  466. }
  467. public static int BinarySearch<T>(T[] array, T value)
  468. {
  469. if (array == null)
  470. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
  471. return BinarySearch<T>(array, 0, array.Length, value, null);
  472. }
  473. public static int BinarySearch<T>(T[] array, T value, System.Collections.Generic.IComparer<T>? comparer)
  474. {
  475. if (array == null)
  476. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
  477. return BinarySearch<T>(array, 0, array.Length, value, comparer);
  478. }
  479. public static int BinarySearch<T>(T[] array, int index, int length, T value)
  480. {
  481. return BinarySearch<T>(array, index, length, value, null);
  482. }
  483. public static int BinarySearch<T>(T[] array, int index, int length, T value, System.Collections.Generic.IComparer<T>? comparer)
  484. {
  485. if (array == null)
  486. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
  487. if (index < 0)
  488. ThrowHelper.ThrowIndexArgumentOutOfRange_NeedNonNegNumException();
  489. if (length < 0)
  490. ThrowHelper.ThrowLengthArgumentOutOfRange_ArgumentOutOfRange_NeedNonNegNum();
  491. if (array.Length - index < length)
  492. ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidOffLen);
  493. return ArraySortHelper<T>.Default.BinarySearch(array, index, length, value, comparer);
  494. }
  495. public static TOutput[] ConvertAll<TInput, TOutput>(TInput[] array, Converter<TInput, TOutput> converter)
  496. {
  497. if (array == null)
  498. {
  499. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
  500. }
  501. if (converter == null)
  502. {
  503. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.converter);
  504. }
  505. TOutput[] newArray = new TOutput[array.Length];
  506. for (int i = 0; i < array.Length; i++)
  507. {
  508. newArray[i] = converter(array[i]);
  509. }
  510. return newArray;
  511. }
  512. // CopyTo copies a collection into an Array, starting at a particular
  513. // index into the array.
  514. //
  515. // This method is to support the ICollection interface, and calls
  516. // Array.Copy internally. If you aren't using ICollection explicitly,
  517. // call Array.Copy to avoid an extra indirection.
  518. //
  519. public void CopyTo(Array array, int index)
  520. {
  521. if (array != null && array.Rank != 1)
  522. ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_RankMultiDimNotSupported);
  523. // Note: Array.Copy throws a RankException and we want a consistent ArgumentException for all the IList CopyTo methods.
  524. Array.Copy(this, GetLowerBound(0), array!, index, Length);
  525. }
  526. public void CopyTo(Array array, long index)
  527. {
  528. int iindex = (int)index;
  529. if (index != iindex)
  530. ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index, ExceptionResource.ArgumentOutOfRange_HugeArrayNotSupported);
  531. this.CopyTo(array, iindex);
  532. }
  533. private static class EmptyArray<T>
  534. {
  535. internal static readonly T[] Value = new T[0];
  536. }
  537. public static T[] Empty<T>()
  538. {
  539. return EmptyArray<T>.Value;
  540. }
  541. public static bool Exists<T>(T[] array, Predicate<T> match)
  542. {
  543. return Array.FindIndex(array, match) != -1;
  544. }
  545. public static void Fill<T>(T[] array, T value)
  546. {
  547. if (array == null)
  548. {
  549. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
  550. }
  551. for (int i = 0; i < array.Length; i++)
  552. {
  553. array[i] = value;
  554. }
  555. }
  556. public static void Fill<T>(T[] array, T value, int startIndex, int count)
  557. {
  558. if (array == null)
  559. {
  560. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
  561. }
  562. if (startIndex < 0 || startIndex > array.Length)
  563. {
  564. ThrowHelper.ThrowStartIndexArgumentOutOfRange_ArgumentOutOfRange_Index();
  565. }
  566. if (count < 0 || startIndex > array.Length - count)
  567. {
  568. ThrowHelper.ThrowCountArgumentOutOfRange_ArgumentOutOfRange_Count();
  569. }
  570. for (int i = startIndex; i < startIndex + count; i++)
  571. {
  572. array[i] = value;
  573. }
  574. }
  575. [return: MaybeNull]
  576. public static T Find<T>(T[] array, Predicate<T> match)
  577. {
  578. if (array == null)
  579. {
  580. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
  581. }
  582. if (match == null)
  583. {
  584. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match);
  585. }
  586. for (int i = 0; i < array.Length; i++)
  587. {
  588. if (match(array[i]))
  589. {
  590. return array[i];
  591. }
  592. }
  593. return default!;
  594. }
  595. public static T[] FindAll<T>(T[] array, Predicate<T> match)
  596. {
  597. if (array == null)
  598. {
  599. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
  600. }
  601. if (match == null)
  602. {
  603. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match);
  604. }
  605. List<T> list = new List<T>();
  606. for (int i = 0; i < array.Length; i++)
  607. {
  608. if (match(array[i]))
  609. {
  610. list.Add(array[i]);
  611. }
  612. }
  613. return list.ToArray();
  614. }
  615. public static int FindIndex<T>(T[] array, Predicate<T> match)
  616. {
  617. if (array == null)
  618. {
  619. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
  620. }
  621. return FindIndex(array, 0, array.Length, match);
  622. }
  623. public static int FindIndex<T>(T[] array, int startIndex, Predicate<T> match)
  624. {
  625. if (array == null)
  626. {
  627. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
  628. }
  629. return FindIndex(array, startIndex, array.Length - startIndex, match);
  630. }
  631. public static int FindIndex<T>(T[] array, int startIndex, int count, Predicate<T> match)
  632. {
  633. if (array == null)
  634. {
  635. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
  636. }
  637. if (startIndex < 0 || startIndex > array.Length)
  638. {
  639. ThrowHelper.ThrowStartIndexArgumentOutOfRange_ArgumentOutOfRange_Index();
  640. }
  641. if (count < 0 || startIndex > array.Length - count)
  642. {
  643. ThrowHelper.ThrowCountArgumentOutOfRange_ArgumentOutOfRange_Count();
  644. }
  645. if (match == null)
  646. {
  647. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match);
  648. }
  649. int endIndex = startIndex + count;
  650. for (int i = startIndex; i < endIndex; i++)
  651. {
  652. if (match!(array[i]))
  653. return i;
  654. }
  655. return -1;
  656. }
  657. [return: MaybeNull]
  658. public static T FindLast<T>(T[] array, Predicate<T> match)
  659. {
  660. if (array == null)
  661. {
  662. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
  663. }
  664. if (match == null)
  665. {
  666. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match);
  667. }
  668. for (int i = array.Length - 1; i >= 0; i--)
  669. {
  670. if (match(array[i]))
  671. {
  672. return array[i];
  673. }
  674. }
  675. return default!;
  676. }
  677. public static int FindLastIndex<T>(T[] array, Predicate<T> match)
  678. {
  679. if (array == null)
  680. {
  681. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
  682. }
  683. return FindLastIndex(array, array.Length - 1, array.Length, match);
  684. }
  685. public static int FindLastIndex<T>(T[] array, int startIndex, Predicate<T> match)
  686. {
  687. if (array == null)
  688. {
  689. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
  690. }
  691. return FindLastIndex(array, startIndex, startIndex + 1, match);
  692. }
  693. public static int FindLastIndex<T>(T[] array, int startIndex, int count, Predicate<T> match)
  694. {
  695. if (array == null)
  696. {
  697. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
  698. }
  699. if (match == null)
  700. {
  701. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match);
  702. }
  703. if (array.Length == 0)
  704. {
  705. // Special case for 0 length List
  706. if (startIndex != -1)
  707. {
  708. ThrowHelper.ThrowStartIndexArgumentOutOfRange_ArgumentOutOfRange_Index();
  709. }
  710. }
  711. else
  712. {
  713. // Make sure we're not out of range
  714. if (startIndex < 0 || startIndex >= array.Length)
  715. {
  716. ThrowHelper.ThrowStartIndexArgumentOutOfRange_ArgumentOutOfRange_Index();
  717. }
  718. }
  719. // 2nd have of this also catches when startIndex == MAXINT, so MAXINT - 0 + 1 == -1, which is < 0.
  720. if (count < 0 || startIndex - count + 1 < 0)
  721. {
  722. ThrowHelper.ThrowCountArgumentOutOfRange_ArgumentOutOfRange_Count();
  723. }
  724. int endIndex = startIndex - count;
  725. for (int i = startIndex; i > endIndex; i--)
  726. {
  727. if (match(array[i]))
  728. {
  729. return i;
  730. }
  731. }
  732. return -1;
  733. }
  734. public static void ForEach<T>(T[] array, Action<T> action)
  735. {
  736. if (array == null)
  737. {
  738. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
  739. }
  740. if (action == null)
  741. {
  742. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.action);
  743. }
  744. for (int i = 0; i < array.Length; i++)
  745. {
  746. action(array[i]);
  747. }
  748. }
  749. // Returns the index of the first occurrence of a given value in an array.
  750. // The array is searched forwards, and the elements of the array are
  751. // compared to the given value using the Object.Equals method.
  752. //
  753. public static int IndexOf(Array array, object? value)
  754. {
  755. if (array == null)
  756. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
  757. return IndexOf(array, value, array.GetLowerBound(0), array.Length);
  758. }
  759. // Returns the index of the first occurrence of a given value in a range of
  760. // an array. The array is searched forwards, starting at index
  761. // startIndex and ending at the last element of the array. The
  762. // elements of the array are compared to the given value using the
  763. // Object.Equals method.
  764. //
  765. public static int IndexOf(Array array, object? value, int startIndex)
  766. {
  767. if (array == null)
  768. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
  769. int lb = array.GetLowerBound(0);
  770. return IndexOf(array, value, startIndex, array.Length - startIndex + lb);
  771. }
  772. // Returns the index of the first occurrence of a given value in a range of
  773. // an array. The array is searched forwards, starting at index
  774. // startIndex and upto count elements. The
  775. // elements of the array are compared to the given value using the
  776. // Object.Equals method.
  777. //
  778. public static int IndexOf(Array array, object? value, int startIndex, int count)
  779. {
  780. if (array == null)
  781. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
  782. if (array.Rank != 1)
  783. ThrowHelper.ThrowRankException(ExceptionResource.Rank_MultiDimNotSupported);
  784. int lb = array.GetLowerBound(0);
  785. if (startIndex < lb || startIndex > array.Length + lb)
  786. ThrowHelper.ThrowStartIndexArgumentOutOfRange_ArgumentOutOfRange_Index();
  787. if (count < 0 || count > array.Length - startIndex + lb)
  788. ThrowHelper.ThrowCountArgumentOutOfRange_ArgumentOutOfRange_Count();
  789. #if CORECLR
  790. // Try calling a quick native method to handle primitive types.
  791. int retVal;
  792. bool r = TrySZIndexOf(array, startIndex, count, value, out retVal);
  793. if (r)
  794. return retVal;
  795. #endif
  796. object[]? objArray = array as object[];
  797. int endIndex = startIndex + count;
  798. if (objArray != null)
  799. {
  800. if (value == null)
  801. {
  802. for (int i = startIndex; i < endIndex; i++)
  803. {
  804. if (objArray[i] == null)
  805. return i;
  806. }
  807. }
  808. else
  809. {
  810. for (int i = startIndex; i < endIndex; i++)
  811. {
  812. object obj = objArray[i];
  813. if (obj != null && obj.Equals(value))
  814. return i;
  815. }
  816. }
  817. }
  818. else
  819. {
  820. for (int i = startIndex; i < endIndex; i++)
  821. {
  822. object? obj = array.GetValue(i);
  823. if (obj == null)
  824. {
  825. if (value == null)
  826. return i;
  827. }
  828. else
  829. {
  830. if (obj.Equals(value))
  831. return i;
  832. }
  833. }
  834. }
  835. // Return one less than the lower bound of the array. This way,
  836. // for arrays with a lower bound of -1 we will not return -1 when the
  837. // item was not found. And for SZArrays (the vast majority), -1 still
  838. // works for them.
  839. return lb - 1;
  840. }
  841. public static int IndexOf<T>(T[] array, T value)
  842. {
  843. if (array == null)
  844. {
  845. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
  846. }
  847. return IndexOf(array, value, 0, array.Length);
  848. }
  849. public static int IndexOf<T>(T[] array, T value, int startIndex)
  850. {
  851. if (array == null)
  852. {
  853. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
  854. }
  855. return IndexOf(array, value, startIndex, array.Length - startIndex);
  856. }
  857. public static int IndexOf<T>(T[] array, T value, int startIndex, int count)
  858. {
  859. if (array == null)
  860. {
  861. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
  862. }
  863. if ((uint)startIndex > (uint)array.Length)
  864. {
  865. ThrowHelper.ThrowStartIndexArgumentOutOfRange_ArgumentOutOfRange_Index();
  866. }
  867. if ((uint)count > (uint)(array.Length - startIndex))
  868. {
  869. ThrowHelper.ThrowCountArgumentOutOfRange_ArgumentOutOfRange_Count();
  870. }
  871. // Hits a code generation bug on ProjectN
  872. #if !PROJECTN
  873. if (RuntimeHelpers.IsBitwiseEquatable<T>())
  874. {
  875. if (Unsafe.SizeOf<T>() == sizeof(byte))
  876. {
  877. int result = SpanHelpers.IndexOf(
  878. ref Unsafe.Add(ref array.GetRawSzArrayData(), startIndex),
  879. Unsafe.As<T, byte>(ref value),
  880. count);
  881. return (result >= 0 ? startIndex : 0) + result;
  882. }
  883. else if (Unsafe.SizeOf<T>() == sizeof(char))
  884. {
  885. int result = SpanHelpers.IndexOf(
  886. ref Unsafe.Add(ref Unsafe.As<byte, char>(ref array.GetRawSzArrayData()), startIndex),
  887. Unsafe.As<T, char>(ref value),
  888. count);
  889. return (result >= 0 ? startIndex : 0) + result;
  890. }
  891. else if (Unsafe.SizeOf<T>() == sizeof(int))
  892. {
  893. int result = SpanHelpers.IndexOf(
  894. ref Unsafe.Add(ref Unsafe.As<byte, int>(ref array.GetRawSzArrayData()), startIndex),
  895. Unsafe.As<T, int>(ref value),
  896. count);
  897. return (result >= 0 ? startIndex : 0) + result;
  898. }
  899. else if (Unsafe.SizeOf<T>() == sizeof(long))
  900. {
  901. int result = SpanHelpers.IndexOf(
  902. ref Unsafe.Add(ref Unsafe.As<byte, long>(ref array.GetRawSzArrayData()), startIndex),
  903. Unsafe.As<T, long>(ref value),
  904. count);
  905. return (result >= 0 ? startIndex : 0) + result;
  906. }
  907. }
  908. #endif
  909. #if CORECLR
  910. return EqualityComparer<T>.Default.IndexOf(array, value, startIndex, count);
  911. #else
  912. return IndexOfImpl(array, value, startIndex, count);
  913. #endif
  914. }
  915. // Returns the index of the last occurrence of a given value in an array.
  916. // The array is searched backwards, and the elements of the array are
  917. // compared to the given value using the Object.Equals method.
  918. //
  919. public static int LastIndexOf(Array array, object? value)
  920. {
  921. if (array == null)
  922. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
  923. int lb = array.GetLowerBound(0);
  924. return LastIndexOf(array, value, array.Length - 1 + lb, array.Length);
  925. }
  926. // Returns the index of the last occurrence of a given value in a range of
  927. // an array. The array is searched backwards, starting at index
  928. // startIndex and ending at index 0. The elements of the array are
  929. // compared to the given value using the Object.Equals method.
  930. //
  931. public static int LastIndexOf(Array array, object? value, int startIndex)
  932. {
  933. if (array == null)
  934. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
  935. int lb = array.GetLowerBound(0);
  936. return LastIndexOf(array, value, startIndex, startIndex + 1 - lb);
  937. }
  938. // Returns the index of the last occurrence of a given value in a range of
  939. // an array. The array is searched backwards, starting at index
  940. // startIndex and counting uptocount elements. The elements of
  941. // the array are compared to the given value using the Object.Equals
  942. // method.
  943. //
  944. public static int LastIndexOf(Array array, object? value, int startIndex, int count)
  945. {
  946. if (array == null)
  947. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
  948. int lb = array.GetLowerBound(0);
  949. if (array.Length == 0)
  950. {
  951. return lb - 1;
  952. }
  953. if (startIndex < lb || startIndex >= array.Length + lb)
  954. ThrowHelper.ThrowStartIndexArgumentOutOfRange_ArgumentOutOfRange_Index();
  955. if (count < 0)
  956. ThrowHelper.ThrowCountArgumentOutOfRange_ArgumentOutOfRange_Count();
  957. if (count > startIndex - lb + 1)
  958. ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.endIndex, ExceptionResource.ArgumentOutOfRange_EndIndexStartIndex);
  959. if (array.Rank != 1)
  960. ThrowHelper.ThrowRankException(ExceptionResource.Rank_MultiDimNotSupported);
  961. #if CORECLR
  962. // Try calling a quick native method to handle primitive types.
  963. int retVal;
  964. bool r = TrySZLastIndexOf(array, startIndex, count, value, out retVal);
  965. if (r)
  966. return retVal;
  967. #endif
  968. object[]? objArray = array as object[];
  969. int endIndex = startIndex - count + 1;
  970. if (objArray != null)
  971. {
  972. if (value == null)
  973. {
  974. for (int i = startIndex; i >= endIndex; i--)
  975. {
  976. if (objArray[i] == null)
  977. return i;
  978. }
  979. }
  980. else
  981. {
  982. for (int i = startIndex; i >= endIndex; i--)
  983. {
  984. object obj = objArray[i];
  985. if (obj != null && obj.Equals(value))
  986. return i;
  987. }
  988. }
  989. }
  990. else
  991. {
  992. for (int i = startIndex; i >= endIndex; i--)
  993. {
  994. object? obj = array.GetValue(i);
  995. if (obj == null)
  996. {
  997. if (value == null)
  998. return i;
  999. }
  1000. else
  1001. {
  1002. if (obj.Equals(value))
  1003. return i;
  1004. }
  1005. }
  1006. }
  1007. return lb - 1; // Return lb-1 for arrays with negative lower bounds.
  1008. }
  1009. public static int LastIndexOf<T>(T[] array, T value)
  1010. {
  1011. if (array == null)
  1012. {
  1013. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
  1014. }
  1015. return LastIndexOf(array, value, array.Length - 1, array.Length);
  1016. }
  1017. public static int LastIndexOf<T>(T[] array, T value, int startIndex)
  1018. {
  1019. if (array == null)
  1020. {
  1021. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
  1022. }
  1023. // if array is empty and startIndex is 0, we need to pass 0 as count
  1024. return LastIndexOf(array, value, startIndex, (array.Length == 0) ? 0 : (startIndex + 1));
  1025. }
  1026. public static int LastIndexOf<T>(T[] array, T value, int startIndex, int count)
  1027. {
  1028. if (array == null)
  1029. {
  1030. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
  1031. }
  1032. if (array.Length == 0)
  1033. {
  1034. //
  1035. // Special case for 0 length List
  1036. // accept -1 and 0 as valid startIndex for compablility reason.
  1037. //
  1038. if (startIndex != -1 && startIndex != 0)
  1039. {
  1040. ThrowHelper.ThrowStartIndexArgumentOutOfRange_ArgumentOutOfRange_Index();
  1041. }
  1042. // only 0 is a valid value for count if array is empty
  1043. if (count != 0)
  1044. {
  1045. ThrowHelper.ThrowCountArgumentOutOfRange_ArgumentOutOfRange_Count();
  1046. }
  1047. return -1;
  1048. }
  1049. // Make sure we're not out of range
  1050. if ((uint)startIndex >= (uint)array.Length)
  1051. {
  1052. ThrowHelper.ThrowStartIndexArgumentOutOfRange_ArgumentOutOfRange_Index();
  1053. }
  1054. // 2nd have of this also catches when startIndex == MAXINT, so MAXINT - 0 + 1 == -1, which is < 0.
  1055. if (count < 0 || startIndex - count + 1 < 0)
  1056. {
  1057. ThrowHelper.ThrowCountArgumentOutOfRange_ArgumentOutOfRange_Count();
  1058. }
  1059. // Hits a code generation bug on ProjectN
  1060. #if !PROJECTN
  1061. if (RuntimeHelpers.IsBitwiseEquatable<T>())
  1062. {
  1063. if (Unsafe.SizeOf<T>() == sizeof(byte))
  1064. {
  1065. int endIndex = startIndex - count + 1;
  1066. int result = SpanHelpers.LastIndexOf(
  1067. ref Unsafe.Add(ref array.GetRawSzArrayData(), endIndex),
  1068. Unsafe.As<T, byte>(ref value),
  1069. count);
  1070. return (result >= 0 ? endIndex : 0) + result;
  1071. }
  1072. else if (Unsafe.SizeOf<T>() == sizeof(char))
  1073. {
  1074. int endIndex = startIndex - count + 1;
  1075. int result = SpanHelpers.LastIndexOf(
  1076. ref Unsafe.Add(ref Unsafe.As<byte, char>(ref array.GetRawSzArrayData()), endIndex),
  1077. Unsafe.As<T, char>(ref value),
  1078. count);
  1079. return (result >= 0 ? endIndex : 0) + result;
  1080. }
  1081. else if (Unsafe.SizeOf<T>() == sizeof(int))
  1082. {
  1083. int endIndex = startIndex - count + 1;
  1084. int result = SpanHelpers.LastIndexOf(
  1085. ref Unsafe.Add(ref Unsafe.As<byte, int>(ref array.GetRawSzArrayData()), endIndex),
  1086. Unsafe.As<T, int>(ref value),
  1087. count);
  1088. return (result >= 0 ? endIndex : 0) + result;
  1089. }
  1090. else if (Unsafe.SizeOf<T>() == sizeof(long))
  1091. {
  1092. int endIndex = startIndex - count + 1;
  1093. int result = SpanHelpers.LastIndexOf(
  1094. ref Unsafe.Add(ref Unsafe.As<byte, long>(ref array.GetRawSzArrayData()), endIndex),
  1095. Unsafe.As<T, long>(ref value),
  1096. count);
  1097. return (result >= 0 ? endIndex : 0) + result;
  1098. }
  1099. }
  1100. #endif
  1101. #if CORECLR
  1102. return EqualityComparer<T>.Default.LastIndexOf(array, value, startIndex, count);
  1103. #else
  1104. return LastIndexOfImpl(array, value, startIndex, count);
  1105. #endif
  1106. }
  1107. // Reverses all elements of the given array. Following a call to this
  1108. // method, an element previously located at index i will now be
  1109. // located at index length - i - 1, where length is the
  1110. // length of the array.
  1111. //
  1112. public static void Reverse(Array array)
  1113. {
  1114. if (array == null)
  1115. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
  1116. Reverse(array, array.GetLowerBound(0), array.Length);
  1117. }
  1118. // Reverses the elements in a range of an array. Following a call to this
  1119. // method, an element in the range given by index and count
  1120. // which was previously located at index i will now be located at
  1121. // index index + (index + count - i - 1).
  1122. // Reliability note: This may fail because it may have to box objects.
  1123. //
  1124. public static void Reverse(Array array, int index, int length)
  1125. {
  1126. if (array == null)
  1127. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
  1128. int lowerBound = array.GetLowerBound(0);
  1129. if (index < lowerBound)
  1130. ThrowHelper.ThrowIndexArgumentOutOfRange_NeedNonNegNumException();
  1131. if (length < 0)
  1132. ThrowHelper.ThrowLengthArgumentOutOfRange_ArgumentOutOfRange_NeedNonNegNum();
  1133. if (array.Length - (index - lowerBound) < length)
  1134. ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidOffLen);
  1135. if (array.Rank != 1)
  1136. ThrowHelper.ThrowRankException(ExceptionResource.Rank_MultiDimNotSupported);
  1137. if (length <= 1)
  1138. return;
  1139. #if CORECLR
  1140. bool r = TrySZReverse(array, index, length);
  1141. if (r)
  1142. return;
  1143. #endif
  1144. if (array is object[] objArray)
  1145. {
  1146. Array.Reverse<object>(objArray, index, length);
  1147. }
  1148. else
  1149. {
  1150. int i = index;
  1151. int j = index + length - 1;
  1152. while (i < j)
  1153. {
  1154. object? temp = array.GetValue(i);
  1155. array.SetValue(array.GetValue(j), i);
  1156. array.SetValue(temp, j);
  1157. i++;
  1158. j--;
  1159. }
  1160. }
  1161. }
  1162. public static void Reverse<T>(T[] array)
  1163. {
  1164. if (array == null)
  1165. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
  1166. Reverse(array, 0, array.Length);
  1167. }
  1168. public static void Reverse<T>(T[] array, int index, int length)
  1169. {
  1170. if (array == null)
  1171. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
  1172. if (index < 0)
  1173. ThrowHelper.ThrowIndexArgumentOutOfRange_NeedNonNegNumException();
  1174. if (length < 0)
  1175. ThrowHelper.ThrowLengthArgumentOutOfRange_ArgumentOutOfRange_NeedNonNegNum();
  1176. if (array.Length - index < length)
  1177. ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidOffLen);
  1178. if (length <= 1)
  1179. return;
  1180. ref T first = ref Unsafe.Add(ref Unsafe.As<byte, T>(ref array.GetRawSzArrayData()), index);
  1181. ref T last = ref Unsafe.Add(ref Unsafe.Add(ref first, length), -1);
  1182. do
  1183. {
  1184. T temp = first;
  1185. first = last;
  1186. last = temp;
  1187. first = ref Unsafe.Add(ref first, 1);
  1188. last = ref Unsafe.Add(ref last, -1);
  1189. } while (Unsafe.IsAddressLessThan(ref first, ref last));
  1190. }
  1191. // Sorts the elements of an array. The sort compares the elements to each
  1192. // other using the IComparable interface, which must be implemented
  1193. // by all elements of the array.
  1194. //
  1195. public static void Sort(Array array)
  1196. {
  1197. if (array == null)
  1198. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
  1199. Sort(array, null, array.GetLowerBound(0), array.Length, null);
  1200. }
  1201. // Sorts the elements of two arrays based on the keys in the first array.
  1202. // Elements in the keys array specify the sort keys for
  1203. // corresponding elements in the items array. The sort compares the
  1204. // keys to each other using the IComparable interface, which must be
  1205. // implemented by all elements of the keys array.
  1206. //
  1207. public static void Sort(Array keys, Array? items)
  1208. {
  1209. if (keys == null)
  1210. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.keys);
  1211. Sort(keys, items, keys.GetLowerBound(0), keys.Length, null);
  1212. }
  1213. // Sorts the elements in a section of an array. The sort compares the
  1214. // elements to each other using the IComparable interface, which
  1215. // must be implemented by all elements in the given section of the array.
  1216. //
  1217. public static void Sort(Array array, int index, int length)
  1218. {
  1219. Sort(array, null, index, length, null);
  1220. }
  1221. // Sorts the elements in a section of two arrays based on the keys in the
  1222. // first array. Elements in the keys array specify the sort keys for
  1223. // corresponding elements in the items array. The sort compares the
  1224. // keys to each other using the IComparable interface, which must be
  1225. // implemented by all elements of the keys array.
  1226. //
  1227. public static void Sort(Array keys, Array? items, int index, int length)
  1228. {
  1229. Sort(keys, items, index, length, null);
  1230. }
  1231. // Sorts the elements of an array. The sort compares the elements to each
  1232. // other using the given IComparer interface. If comparer is
  1233. // null, the elements are compared to each other using the
  1234. // IComparable interface, which in that case must be implemented by
  1235. // all elements of the array.
  1236. //
  1237. public static void Sort(Array array, IComparer? comparer)
  1238. {
  1239. if (array == null)
  1240. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
  1241. Sort(array!, null, array!.GetLowerBound(0), array.Length, comparer);
  1242. }
  1243. // Sorts the elements of two arrays based on the keys in the first array.
  1244. // Elements in the keys array specify the sort keys for
  1245. // corresponding elements in the items array. The sort compares the
  1246. // keys to each other using the given IComparer interface. If
  1247. // comparer is null, the elements are compared to each other using
  1248. // the IComparable interface, which in that case must be implemented
  1249. // by all elements of the keys array.
  1250. //
  1251. public static void Sort(Array keys, Array? items, IComparer? comparer)
  1252. {
  1253. if (keys == null)
  1254. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.keys);
  1255. Sort(keys, items, keys.GetLowerBound(0), keys.Length, comparer);
  1256. }
  1257. // Sorts the elements in a section of an array. The sort compares the
  1258. // elements to each other using the given IComparer interface. If
  1259. // comparer is null, the elements are compared to each other using
  1260. // the IComparable interface, which in that case must be implemented
  1261. // by all elements in the given section of the array.
  1262. //
  1263. public static void Sort(Array array, int index, int length, IComparer? comparer)
  1264. {
  1265. Sort(array, null, index, length, comparer);
  1266. }
  1267. // Sorts the elements in a section of two arrays based on the keys in the
  1268. // first array. Elements in the keys array specify the sort keys for
  1269. // corresponding elements in the items array. The sort compares the
  1270. // keys to each other using the given IComparer interface. If
  1271. // comparer is null, the elements are compared to each other using
  1272. // the IComparable interface, which in that case must be implemented
  1273. // by all elements of the given section of the keys array.
  1274. //
  1275. public static void Sort(Array keys, Array? items, int index, int length, IComparer? comparer)
  1276. {
  1277. if (keys == null)
  1278. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.keys);
  1279. if (keys.Rank != 1 || (items != null && items.Rank != 1))
  1280. ThrowHelper.ThrowRankException(ExceptionResource.Rank_MultiDimNotSupported);
  1281. int keysLowerBound = keys.GetLowerBound(0);
  1282. if (items != null && keysLowerBound != items.GetLowerBound(0))
  1283. ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_LowerBoundsMustMatch);
  1284. if (index < keysLowerBound)
  1285. ThrowHelper.ThrowIndexArgumentOutOfRange_NeedNonNegNumException();
  1286. if (length < 0)
  1287. ThrowHelper.ThrowLengthArgumentOutOfRange_ArgumentOutOfRange_NeedNonNegNum();
  1288. if (keys.Length - (index - keysLowerBound) < length || (items != null && (index - keysLowerBound) > items.Length - length))
  1289. ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidOffLen);
  1290. if (length > 1)
  1291. {
  1292. SortImpl(keys, items, index, length, comparer ?? Comparer.Default);
  1293. }
  1294. }
  1295. public static void Sort<T>(T[] array)
  1296. {
  1297. if (array == null)
  1298. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
  1299. Sort<T>(array, 0, array.Length, null);
  1300. }
  1301. public static void Sort<TKey, TValue>(TKey[] keys, TValue[]? items)
  1302. {
  1303. if (keys == null)
  1304. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.keys);
  1305. Sort<TKey, TValue>(keys, items, 0, keys.Length, null);
  1306. }
  1307. public static void Sort<T>(T[] array, int index, int length)
  1308. {
  1309. Sort<T>(array, index, length, null);
  1310. }
  1311. public static void Sort<TKey, TValue>(TKey[] keys, TValue[]? items, int index, int length)
  1312. {
  1313. Sort<TKey, TValue>(keys, items, index, length, null);
  1314. }
  1315. public static void Sort<T>(T[] array, System.Collections.Generic.IComparer<T>? comparer)
  1316. {
  1317. if (array == null)
  1318. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
  1319. Sort<T>(array, 0, array.Length, comparer);
  1320. }
  1321. public static void Sort<TKey, TValue>(TKey[] keys, TValue[]? items, System.Collections.Generic.IComparer<TKey>? comparer)
  1322. {
  1323. if (keys == null)
  1324. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.keys);
  1325. Sort<TKey, TValue>(keys, items, 0, keys.Length, comparer);
  1326. }
  1327. public static void Sort<T>(T[] array, int index, int length, System.Collections.Generic.IComparer<T>? comparer)
  1328. {
  1329. if (array == null)
  1330. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
  1331. if (index < 0)
  1332. ThrowHelper.ThrowIndexArgumentOutOfRange_NeedNonNegNumException();
  1333. if (length < 0)
  1334. ThrowHelper.ThrowLengthArgumentOutOfRange_ArgumentOutOfRange_NeedNonNegNum();
  1335. if (array.Length - index < length)
  1336. ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidOffLen);
  1337. if (length > 1)
  1338. {
  1339. #if CORECLR
  1340. if (comparer == null || comparer == Comparer<T>.Default)
  1341. {
  1342. if (TrySZSort(array, null, index, index + length - 1))
  1343. {
  1344. return;
  1345. }
  1346. }
  1347. #endif
  1348. ArraySortHelper<T>.Default.Sort(array, index, length, comparer);
  1349. }
  1350. }
  1351. public static void Sort<TKey, TValue>(TKey[] keys, TValue[]? items, int index, int length, System.Collections.Generic.IComparer<TKey>? comparer)
  1352. {
  1353. if (keys == null)
  1354. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.keys);
  1355. if (index < 0)
  1356. ThrowHelper.ThrowIndexArgumentOutOfRange_NeedNonNegNumException();
  1357. if (length < 0)
  1358. ThrowHelper.ThrowLengthArgumentOutOfRange_ArgumentOutOfRange_NeedNonNegNum();
  1359. if (keys.Length - index < length || (items != null && index > items.Length - length))
  1360. ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidOffLen);
  1361. if (length > 1)
  1362. {
  1363. #if CORECLR
  1364. if (comparer == null || comparer == Comparer<TKey>.Default)
  1365. {
  1366. if (TrySZSort(keys, items, index, index + length - 1))
  1367. {
  1368. return;
  1369. }
  1370. }
  1371. #endif
  1372. if (items == null)
  1373. {
  1374. Sort<TKey>(keys, index, length, comparer);
  1375. return;
  1376. }
  1377. ArraySortHelper<TKey, TValue>.Default.Sort(keys, items, index, length, comparer);
  1378. }
  1379. }
  1380. public static void Sort<T>(T[] array, Comparison<T> comparison)
  1381. {
  1382. if (array == null)
  1383. {
  1384. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
  1385. }
  1386. if (comparison == null)
  1387. {
  1388. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.comparison);
  1389. }
  1390. ArraySortHelper<T>.Sort(array, 0, array.Length, comparison!);
  1391. }
  1392. public static bool TrueForAll<T>(T[] array, Predicate<T> match)
  1393. {
  1394. if (array == null)
  1395. {
  1396. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
  1397. }
  1398. if (match == null)
  1399. {
  1400. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match);
  1401. }
  1402. for (int i = 0; i < array.Length; i++)
  1403. {
  1404. if (!match(array[i]))
  1405. {
  1406. return false;
  1407. }
  1408. }
  1409. return true;
  1410. }
  1411. #if !CORERT
  1412. // Private value type used by the Sort methods.
  1413. private readonly struct SorterObjectArray
  1414. {
  1415. private readonly object[] keys;
  1416. private readonly object?[]? items;
  1417. private readonly IComparer comparer;
  1418. internal SorterObjectArray(object[] keys, object?[]? items, IComparer comparer)
  1419. {
  1420. this.keys = keys;
  1421. this.items = items;
  1422. this.comparer = comparer;
  1423. }
  1424. internal void SwapIfGreaterWithItems(int a, int b)
  1425. {
  1426. if (a != b)
  1427. {
  1428. if (comparer.Compare(keys[a], keys[b]) > 0)
  1429. {
  1430. object temp = keys[a];
  1431. keys[a] = keys[b];
  1432. keys[b] = temp;
  1433. if (items != null)
  1434. {
  1435. object? item = items[a];
  1436. items[a] = items[b];
  1437. items[b] = item;
  1438. }
  1439. }
  1440. }
  1441. }
  1442. private void Swap(int i, int j)
  1443. {
  1444. object t = keys[i];
  1445. keys[i] = keys[j];
  1446. keys[j] = t;
  1447. if (items != null)
  1448. {
  1449. object? item = items[i];
  1450. items[i] = items[j];
  1451. items[j] = item;
  1452. }
  1453. }
  1454. internal void Sort(int left, int length)
  1455. {
  1456. IntrospectiveSort(left, length);
  1457. }
  1458. private void IntrospectiveSort(int left, int length)
  1459. {
  1460. if (length < 2)
  1461. return;
  1462. try
  1463. {
  1464. IntroSort(left, length + left - 1, 2 * IntrospectiveSortUtilities.FloorLog2PlusOne(length));
  1465. }
  1466. catch (IndexOutOfRangeException)
  1467. {
  1468. IntrospectiveSortUtilities.ThrowOrIgnoreBadComparer(comparer);
  1469. }
  1470. catch (Exception e)
  1471. {
  1472. ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_IComparerFailed, e);
  1473. }
  1474. }
  1475. private void IntroSort(int lo, int hi, int depthLimit)
  1476. {
  1477. while (hi > lo)
  1478. {
  1479. int partitionSize = hi - lo + 1;
  1480. if (partitionSize <= IntrospectiveSortUtilities.IntrosortSizeThreshold)
  1481. {
  1482. if (partitionSize == 1)
  1483. {
  1484. return;
  1485. }
  1486. if (partitionSize == 2)
  1487. {
  1488. SwapIfGreaterWithItems(lo, hi);
  1489. return;
  1490. }
  1491. if (partitionSize == 3)
  1492. {
  1493. SwapIfGreaterWithItems(lo, hi - 1);
  1494. SwapIfGreaterWithItems(lo, hi);
  1495. SwapIfGreaterWithItems(hi - 1, hi);
  1496. return;
  1497. }
  1498. InsertionSort(lo, hi);
  1499. return;
  1500. }
  1501. if (depthLimit == 0)
  1502. {
  1503. Heapsort(lo, hi);
  1504. return;
  1505. }
  1506. depthLimit--;
  1507. int p = PickPivotAndPartition(lo, hi);
  1508. IntroSort(p + 1, hi, depthLimit);
  1509. hi = p - 1;
  1510. }
  1511. }
  1512. private int PickPivotAndPartition(int lo, int hi)
  1513. {
  1514. // Compute median-of-three. But also partition them, since we've done the comparison.
  1515. int mid = lo + (hi - lo) / 2;
  1516. // Sort lo, mid and hi appropriately, then pick mid as the pivot.
  1517. SwapIfGreaterWithItems(lo, mid);
  1518. SwapIfGreaterWithItems(lo, hi);
  1519. SwapIfGreaterWithItems(mid, hi);
  1520. object pivot = keys[mid];
  1521. Swap(mid, hi - 1);
  1522. 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.
  1523. while (left < right)
  1524. {
  1525. while (comparer.Compare(keys[++left], pivot) < 0) ;
  1526. while (comparer.Compare(pivot, keys[--right]) < 0) ;
  1527. if (left >= right)
  1528. break;
  1529. Swap(left, right);
  1530. }
  1531. // Put pivot in the right location.
  1532. Swap(left, (hi - 1));
  1533. return left;
  1534. }
  1535. private void Heapsort(int lo, int hi)
  1536. {
  1537. int n = hi - lo + 1;
  1538. for (int i = n / 2; i >= 1; i = i - 1)
  1539. {
  1540. DownHeap(i, n, lo);
  1541. }
  1542. for (int i = n; i > 1; i = i - 1)
  1543. {
  1544. Swap(lo, lo + i - 1);
  1545. DownHeap(1, i - 1, lo);
  1546. }
  1547. }
  1548. private void DownHeap(int i, int n, int lo)
  1549. {
  1550. object d = keys[lo + i - 1];
  1551. object? dt = (items != null) ? items[lo + i - 1] : null;
  1552. int child;
  1553. while (i <= n / 2)
  1554. {
  1555. child = 2 * i;
  1556. if (child < n && comparer.Compare(keys[lo + child - 1], keys[lo + child]) < 0)
  1557. {
  1558. child++;
  1559. }
  1560. if (!(comparer.Compare(d, keys[lo + child - 1]) < 0))
  1561. break;
  1562. keys[lo + i - 1] = keys[lo + child - 1];
  1563. if (items != null)
  1564. items[lo + i - 1] = items[lo + child - 1];
  1565. i = child;
  1566. }
  1567. keys[lo + i - 1] = d;
  1568. if (items != null)
  1569. items[lo + i - 1] = dt;
  1570. }
  1571. private void InsertionSort(int lo, int hi)
  1572. {
  1573. int i, j;
  1574. object t;
  1575. object? ti;
  1576. for (i = lo; i < hi; i++)
  1577. {
  1578. j = i;
  1579. t = keys[i + 1];
  1580. ti = (items != null) ? items[i + 1] : null;
  1581. while (j >= lo && comparer.Compare(t, keys[j]) < 0)
  1582. {
  1583. keys[j + 1] = keys[j];
  1584. if (items != null)
  1585. items[j + 1] = items[j];
  1586. j--;
  1587. }
  1588. keys[j + 1] = t;
  1589. if (items != null)
  1590. items[j + 1] = ti;
  1591. }
  1592. }
  1593. }
  1594. // Private value used by the Sort methods for instances of Array.
  1595. // This is slower than the one for Object[], since we can't use the JIT helpers
  1596. // to access the elements. We must use GetValue & SetValue.
  1597. private readonly struct SorterGenericArray
  1598. {
  1599. private readonly Array keys;
  1600. private readonly Array? items;
  1601. private readonly IComparer comparer;
  1602. internal SorterGenericArray(Array keys, Array? items, IComparer comparer)
  1603. {
  1604. this.keys = keys;
  1605. this.items = items;
  1606. this.comparer = comparer;
  1607. }
  1608. internal void SwapIfGreaterWithItems(int a, int b)
  1609. {
  1610. if (a != b)
  1611. {
  1612. if (comparer.Compare(keys.GetValue(a), keys.GetValue(b)) > 0)
  1613. {
  1614. object? key = keys.GetValue(a);
  1615. keys.SetValue(keys.GetValue(b), a);
  1616. keys.SetValue(key, b);
  1617. if (items != null)
  1618. {
  1619. object? item = items.GetValue(a);
  1620. items.SetValue(items.GetValue(b), a);
  1621. items.SetValue(item, b);
  1622. }
  1623. }
  1624. }
  1625. }
  1626. private void Swap(int i, int j)
  1627. {
  1628. object? t1 = keys.GetValue(i);
  1629. keys.SetValue(keys.GetValue(j), i);
  1630. keys.SetValue(t1, j);
  1631. if (items != null)
  1632. {
  1633. object? t2 = items.GetValue(i);
  1634. items.SetValue(items.GetValue(j), i);
  1635. items.SetValue(t2, j);
  1636. }
  1637. }
  1638. internal void Sort(int left, int length)
  1639. {
  1640. IntrospectiveSort(left, length);
  1641. }
  1642. private void IntrospectiveSort(int left, int length)
  1643. {
  1644. if (length < 2)
  1645. return;
  1646. try
  1647. {
  1648. IntroSort(left, length + left - 1, 2 * IntrospectiveSortUtilities.FloorLog2PlusOne(length));
  1649. }
  1650. catch (IndexOutOfRangeException)
  1651. {
  1652. IntrospectiveSortUtilities.ThrowOrIgnoreBadComparer(comparer);
  1653. }
  1654. catch (Exception e)
  1655. {
  1656. ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_IComparerFailed, e);
  1657. }
  1658. }
  1659. private void IntroSort(int lo, int hi, int depthLimit)
  1660. {
  1661. while (hi > lo)
  1662. {
  1663. int partitionSize = hi - lo + 1;
  1664. if (partitionSize <= IntrospectiveSortUtilities.IntrosortSizeThreshold)
  1665. {
  1666. if (partitionSize == 1)
  1667. {
  1668. return;
  1669. }
  1670. if (partitionSize == 2)
  1671. {
  1672. SwapIfGreaterWithItems(lo, hi);
  1673. return;
  1674. }
  1675. if (partitionSize == 3)
  1676. {
  1677. SwapIfGreaterWithItems(lo, hi - 1);
  1678. SwapIfGreaterWithItems(lo, hi);
  1679. SwapIfGreaterWithItems(hi - 1, hi);
  1680. return;
  1681. }
  1682. InsertionSort(lo, hi);
  1683. return;
  1684. }
  1685. if (depthLimit == 0)
  1686. {
  1687. Heapsort(lo, hi);
  1688. return;
  1689. }
  1690. depthLimit--;
  1691. int p = PickPivotAndPartition(lo, hi);
  1692. IntroSort(p + 1, hi, depthLimit);
  1693. hi = p - 1;
  1694. }
  1695. }
  1696. private int PickPivotAndPartition(int lo, int hi)
  1697. {
  1698. // Compute median-of-three. But also partition them, since we've done the comparison.
  1699. int mid = lo + (hi - lo) / 2;
  1700. SwapIfGreaterWithItems(lo, mid);
  1701. SwapIfGreaterWithItems(lo, hi);
  1702. SwapIfGreaterWithItems(mid, hi);
  1703. object? pivot = keys.GetValue(mid);
  1704. Swap(mid, hi - 1);
  1705. 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.
  1706. while (left < right)
  1707. {
  1708. while (comparer.Compare(keys.GetValue(++left), pivot) < 0) ;
  1709. while (comparer.Compare(pivot, keys.GetValue(--right)) < 0) ;
  1710. if (left >= right)
  1711. break;
  1712. Swap(left, right);
  1713. }
  1714. // Put pivot in the right location.
  1715. Swap(left, (hi - 1));
  1716. return left;
  1717. }
  1718. private void Heapsort(int lo, int hi)
  1719. {
  1720. int n = hi - lo + 1;
  1721. for (int i = n / 2; i >= 1; i = i - 1)
  1722. {
  1723. DownHeap(i, n, lo);
  1724. }
  1725. for (int i = n; i > 1; i = i - 1)
  1726. {
  1727. Swap(lo, lo + i - 1);
  1728. DownHeap(1, i - 1, lo);
  1729. }
  1730. }
  1731. private void DownHeap(int i, int n, int lo)
  1732. {
  1733. object? d = keys.GetValue(lo + i - 1);
  1734. object? dt = (items != null) ? items.GetValue(lo + i - 1) : null;
  1735. int child;
  1736. while (i <= n / 2)
  1737. {
  1738. child = 2 * i;
  1739. if (child < n && comparer.Compare(keys.GetValue(lo + child - 1), keys.GetValue(lo + child)) < 0)
  1740. {
  1741. child++;
  1742. }
  1743. if (!(comparer.Compare(d, keys.GetValue(lo + child - 1)) < 0))
  1744. break;
  1745. keys.SetValue(keys.GetValue(lo + child - 1), lo + i - 1);
  1746. if (items != null)
  1747. items.SetValue(items.GetValue(lo + child - 1), lo + i - 1);
  1748. i = child;
  1749. }
  1750. keys.SetValue(d, lo + i - 1);
  1751. if (items != null)
  1752. items.SetValue(dt, lo + i - 1);
  1753. }
  1754. private void InsertionSort(int lo, int hi)
  1755. {
  1756. int i, j;
  1757. object? t;
  1758. object? dt;
  1759. for (i = lo; i < hi; i++)
  1760. {
  1761. j = i;
  1762. t = keys.GetValue(i + 1);
  1763. dt = (items != null) ? items.GetValue(i + 1) : null;
  1764. while (j >= lo && comparer.Compare(t, keys.GetValue(j)) < 0)
  1765. {
  1766. keys.SetValue(keys.GetValue(j), j + 1);
  1767. if (items != null)
  1768. items.SetValue(items.GetValue(j), j + 1);
  1769. j--;
  1770. }
  1771. keys.SetValue(t, j + 1);
  1772. if (items != null)
  1773. items.SetValue(dt, j + 1);
  1774. }
  1775. }
  1776. }
  1777. public IEnumerator GetEnumerator()
  1778. {
  1779. int lowerBound = GetLowerBound(0);
  1780. if (Rank == 1 && lowerBound == 0)
  1781. return new SZArrayEnumerator(this);
  1782. else
  1783. return new ArrayEnumerator(this, lowerBound, Length);
  1784. }
  1785. #endif // !CORERT
  1786. }
  1787. }