BufferPool.cs 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. 
  2. using System.Threading;
  3. namespace ProtoBuf
  4. {
  5. internal sealed class BufferPool
  6. {
  7. internal static void Flush()
  8. {
  9. #if PLAT_NO_INTERLOCKED
  10. lock(pool)
  11. {
  12. for (int i = 0; i < pool.Length; i++) pool[i] = null;
  13. }
  14. #else
  15. for (int i = 0; i < pool.Length; i++)
  16. {
  17. Interlocked.Exchange(ref pool[i], null); // and drop the old value on the floor
  18. }
  19. #endif
  20. }
  21. private BufferPool() { }
  22. const int PoolSize = 20;
  23. internal const int BufferLength = 1024;
  24. private static readonly object[] pool = new object[PoolSize];
  25. internal static byte[] GetBuffer()
  26. {
  27. object tmp;
  28. #if PLAT_NO_INTERLOCKED
  29. lock(pool)
  30. {
  31. for (int i = 0; i < pool.Length; i++)
  32. {
  33. if((tmp = pool[i]) != null)
  34. {
  35. pool[i] = null;
  36. return (byte[])tmp;
  37. }
  38. }
  39. }
  40. #else
  41. for (int i = 0; i < pool.Length; i++)
  42. {
  43. if ((tmp = Interlocked.Exchange(ref pool[i], null)) != null) return (byte[])tmp;
  44. }
  45. #endif
  46. return new byte[BufferLength];
  47. }
  48. internal static void ResizeAndFlushLeft(ref byte[] buffer, int toFitAtLeastBytes, int copyFromIndex, int copyBytes)
  49. {
  50. Helpers.DebugAssert(buffer != null);
  51. Helpers.DebugAssert(toFitAtLeastBytes > buffer.Length);
  52. Helpers.DebugAssert(copyFromIndex >= 0);
  53. Helpers.DebugAssert(copyBytes >= 0);
  54. // try doubling, else match
  55. int newLength = buffer.Length * 2;
  56. if (newLength < toFitAtLeastBytes) newLength = toFitAtLeastBytes;
  57. byte[] newBuffer = new byte[newLength];
  58. if (copyBytes > 0)
  59. {
  60. Helpers.BlockCopy(buffer, copyFromIndex, newBuffer, 0, copyBytes);
  61. }
  62. if (buffer.Length == BufferPool.BufferLength)
  63. {
  64. BufferPool.ReleaseBufferToPool(ref buffer);
  65. }
  66. buffer = newBuffer;
  67. }
  68. internal static void ReleaseBufferToPool(ref byte[] buffer)
  69. {
  70. if (buffer == null) return;
  71. if (buffer.Length == BufferLength)
  72. {
  73. #if PLAT_NO_INTERLOCKED
  74. lock (pool)
  75. {
  76. for (int i = 0; i < pool.Length; i++)
  77. {
  78. if(pool[i] == null)
  79. {
  80. pool[i] = buffer;
  81. break;
  82. }
  83. }
  84. }
  85. #else
  86. for (int i = 0; i < pool.Length; i++)
  87. {
  88. if (Interlocked.CompareExchange(ref pool[i], buffer, null) == null)
  89. {
  90. break; // found a null; swapped it in
  91. }
  92. }
  93. #endif
  94. }
  95. // if no space, just drop it on the floor
  96. buffer = null;
  97. }
  98. }
  99. }