ArrayPoolUtil.cs 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Runtime.CompilerServices;
  5. namespace Cysharp.Threading.Tasks.Internal
  6. {
  7. internal static class ArrayPoolUtil
  8. {
  9. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  10. internal static void EnsureCapacity<T>(ref T[] array, int index, ArrayPool<T> pool)
  11. {
  12. if (array.Length <= index)
  13. {
  14. EnsureCapacityCore(ref array, index, pool);
  15. }
  16. }
  17. [MethodImpl(MethodImplOptions.NoInlining)]
  18. static void EnsureCapacityCore<T>(ref T[] array, int index, ArrayPool<T> pool)
  19. {
  20. if (array.Length <= index)
  21. {
  22. var newSize = array.Length * 2;
  23. var newArray = pool.Rent((index < newSize) ? newSize : (index * 2));
  24. Array.Copy(array, 0, newArray, 0, array.Length);
  25. pool.Return(array, clearArray: !RuntimeHelpersAbstraction.IsWellKnownNoReferenceContainsType<T>());
  26. array = newArray;
  27. }
  28. }
  29. public static RentArray<T> Materialize<T>(IEnumerable<T> source)
  30. {
  31. if (source is T[] array)
  32. {
  33. return new RentArray<T>(array, array.Length, null);
  34. }
  35. var defaultCount = 32;
  36. if (source is ICollection<T> coll)
  37. {
  38. if (coll.Count == 0)
  39. {
  40. return new RentArray<T>(Array.Empty<T>(), 0, null);
  41. }
  42. defaultCount = coll.Count;
  43. var pool = ArrayPool<T>.Shared;
  44. var buffer = pool.Rent(defaultCount);
  45. coll.CopyTo(buffer, 0);
  46. return new RentArray<T>(buffer, coll.Count, pool);
  47. }
  48. else if (source is IReadOnlyCollection<T> rcoll)
  49. {
  50. defaultCount = rcoll.Count;
  51. }
  52. if (defaultCount == 0)
  53. {
  54. return new RentArray<T>(Array.Empty<T>(), 0, null);
  55. }
  56. {
  57. var pool = ArrayPool<T>.Shared;
  58. var index = 0;
  59. var buffer = pool.Rent(defaultCount);
  60. foreach (var item in source)
  61. {
  62. EnsureCapacity(ref buffer, index, pool);
  63. buffer[index++] = item;
  64. }
  65. return new RentArray<T>(buffer, index, pool);
  66. }
  67. }
  68. public struct RentArray<T> : IDisposable
  69. {
  70. public readonly T[] Array;
  71. public readonly int Length;
  72. ArrayPool<T> pool;
  73. public RentArray(T[] array, int length, ArrayPool<T> pool)
  74. {
  75. this.Array = array;
  76. this.Length = length;
  77. this.pool = pool;
  78. }
  79. public void Dispose()
  80. {
  81. DisposeManually(!RuntimeHelpersAbstraction.IsWellKnownNoReferenceContainsType<T>());
  82. }
  83. public void DisposeManually(bool clearArray)
  84. {
  85. if (pool != null)
  86. {
  87. if (clearArray)
  88. {
  89. System.Array.Clear(Array, 0, Length);
  90. }
  91. pool.Return(Array, clearArray: false);
  92. pool = null;
  93. }
  94. }
  95. }
  96. }
  97. }