BufferPool.cs 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. #region Copyright and License
  2. /*
  3. This file is part of FFTW.NET, a wrapper around the FFTW library for the .NET framework.
  4. Copyright (C) 2017 Tobias Meyer
  5. License: Microsoft Reciprocal License (MS-RL)
  6. */
  7. #endregion
  8. using System;
  9. using System.Collections.Generic;
  10. namespace FFTW.NET
  11. {
  12. public class BufferPool<T> where T : struct
  13. {
  14. readonly List<BufferItem> _buffers = new List<BufferItem>();
  15. int _minSize;
  16. /// <summary>
  17. /// Minimum size a buffer must have to be added to the pool.
  18. /// </summary>
  19. public int MinSizeToPool
  20. {
  21. get { return _minSize; }
  22. set
  23. {
  24. if (value < 0)
  25. throw new ArgumentOutOfRangeException(nameof(value), "Must be equal to or greater than 0.");
  26. _minSize = value;
  27. }
  28. }
  29. /// <summary>
  30. /// Minimum size a buffer must have to be added to the pool.
  31. /// </summary>
  32. /// <param name="minSizeToPool"></param>
  33. public BufferPool(int minSizeToPool = 0)
  34. {
  35. MinSizeToPool = minSizeToPool;
  36. }
  37. public Container RequestBuffer(int minSize) => Container.Get(this, minSize);
  38. struct BufferItem
  39. {
  40. readonly int _size;
  41. readonly WeakReference<T[]> _buffer;
  42. public long Size => _size;
  43. public WeakReference<T[]> Buffer => _buffer;
  44. internal BufferItem(T[] buffer)
  45. {
  46. _size = buffer.Length;
  47. _buffer = new WeakReference<T[]>(buffer);
  48. }
  49. }
  50. public struct Container : IDisposable
  51. {
  52. T[]? _buffer;
  53. readonly BufferPool<T> _bufferPool;
  54. public T[]? Buffer => _buffer;
  55. private Container(BufferPool<T> bufferPool, T[] buffer)
  56. {
  57. _buffer = buffer;
  58. _bufferPool = bufferPool;
  59. }
  60. internal static Container Get(BufferPool<T> bufferPool, int minSize)
  61. {
  62. if (minSize < bufferPool.MinSizeToPool)
  63. return new Container(bufferPool, new T[minSize]);
  64. T[]? buffer = null;
  65. lock (bufferPool._buffers)
  66. {
  67. for (int i = 0; i < bufferPool._buffers.Count; i++)
  68. {
  69. BufferItem item = bufferPool._buffers[i];
  70. if (item.Size >= minSize)
  71. {
  72. bufferPool._buffers.RemoveAt(i--);
  73. if (bufferPool._buffers[i].Buffer.TryGetTarget(out buffer))
  74. break;
  75. }
  76. }
  77. }
  78. return new Container(bufferPool, buffer ?? new T[minSize]);
  79. }
  80. public void Dispose()
  81. {
  82. if (_buffer == null)
  83. return;
  84. if (_buffer.Length < _bufferPool.MinSizeToPool)
  85. {
  86. _buffer = null;
  87. return;
  88. }
  89. lock (_bufferPool._buffers)
  90. {
  91. for (int i = 0; i < _bufferPool._buffers.Count; i++)
  92. {
  93. if (_buffer.Length >= _bufferPool._buffers[i].Size)
  94. {
  95. _bufferPool._buffers.Insert(i, new BufferItem(_buffer));
  96. _buffer = null;
  97. break;
  98. }
  99. }
  100. if (_buffer != null)
  101. {
  102. _bufferPool._buffers.Add(new BufferItem(_buffer));
  103. _buffer = null;
  104. }
  105. }
  106. }
  107. }
  108. }
  109. }