StringBuilderPool.cs 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using System.Threading;
  5. using BestHTTP.PlatformSupport.Threading;
  6. namespace BestHTTP.PlatformSupport.Text
  7. {
  8. [BestHTTP.PlatformSupport.IL2CPP.Il2CppEagerStaticClassConstructionAttribute]
  9. public static class StringBuilderPool
  10. {
  11. /// <summary>
  12. /// Setting this property to false the pooling mechanism can be disabled.
  13. /// </summary>
  14. public static bool IsEnabled
  15. {
  16. get { return _isEnabled; }
  17. set
  18. {
  19. _isEnabled = value;
  20. // When set to non-enabled remove all stored entries
  21. if (!_isEnabled)
  22. Clear();
  23. }
  24. }
  25. private static volatile bool _isEnabled = true;
  26. /// <summary>
  27. /// Buffer entries that released back to the pool and older than this value are moved when next maintenance is triggered.
  28. /// </summary>
  29. public static TimeSpan RemoveOlderThan = TimeSpan.FromSeconds(10);
  30. /// <summary>
  31. /// How often pool maintenance must run.
  32. /// </summary>
  33. public static TimeSpan RunMaintenanceEvery = TimeSpan.FromSeconds(5);
  34. private static DateTime lastMaintenance = DateTime.MinValue;
  35. private readonly static ReaderWriterLockSlim rwLock = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion);
  36. struct BuilderShelf
  37. {
  38. public StringBuilder builder;
  39. public DateTime released;
  40. public BuilderShelf(StringBuilder sb)
  41. {
  42. this.builder = sb;
  43. this.released = DateTime.UtcNow;
  44. }
  45. }
  46. private static List<BuilderShelf> pooledBuilders = new List<BuilderShelf>();
  47. public static StringBuilder Get(int lengthHint)
  48. {
  49. if (!_isEnabled)
  50. return new StringBuilder(lengthHint);
  51. using (new WriteLock(rwLock))
  52. {
  53. for (int i = pooledBuilders.Count - 1; i >= 0; i--)
  54. {
  55. BuilderShelf shelf = pooledBuilders[i];
  56. if (shelf.builder.Capacity >= lengthHint)
  57. {
  58. pooledBuilders.RemoveAt(i);
  59. return shelf.builder;
  60. }
  61. }
  62. // no builder found with lengthHint, take the first available
  63. if (pooledBuilders.Count > 0)
  64. {
  65. BuilderShelf shelf = pooledBuilders[pooledBuilders.Count - 1];
  66. pooledBuilders.RemoveAt(pooledBuilders.Count - 1);
  67. return shelf.builder;
  68. }
  69. }
  70. return new StringBuilder(lengthHint);
  71. }
  72. public static void Release(StringBuilder builder)
  73. {
  74. if (builder == null)
  75. return;
  76. if (!_isEnabled)
  77. return;
  78. builder.Clear();
  79. using (new WriteLock(rwLock))
  80. pooledBuilders.Add(new BuilderShelf(builder));
  81. }
  82. public static string ReleaseAndGrab(StringBuilder builder)
  83. {
  84. if (builder == null)
  85. return null;
  86. var result = builder.ToString();
  87. if (!_isEnabled)
  88. return result;
  89. builder.Clear();
  90. using (new WriteLock(rwLock))
  91. pooledBuilders.Add(new BuilderShelf(builder));
  92. return result;
  93. }
  94. internal static void Maintain()
  95. {
  96. DateTime now = DateTime.UtcNow;
  97. if (!_isEnabled || lastMaintenance + RunMaintenanceEvery > now)
  98. return;
  99. lastMaintenance = now;
  100. DateTime olderThan = now - RemoveOlderThan;
  101. using (new WriteLock(rwLock))
  102. {
  103. for (int i = 0; i < pooledBuilders.Count; i++)
  104. {
  105. BuilderShelf shelf = pooledBuilders[i];
  106. if (shelf.released < olderThan)
  107. pooledBuilders.RemoveAt(i--);
  108. }
  109. }
  110. }
  111. public static void Clear()
  112. {
  113. using (new WriteLock(rwLock))
  114. pooledBuilders.Clear();
  115. }
  116. }
  117. }