using System; using System.Collections.Generic; using System.Text; using System.Threading; using Best.HTTP.Shared.PlatformSupport.Threading; namespace Best.HTTP.Shared.PlatformSupport.Text { /// /// Implements pooling logic for instances. /// [Best.HTTP.Shared.PlatformSupport.IL2CPP.Il2CppEagerStaticClassConstructionAttribute] public static class StringBuilderPool { /// /// Setting this property to false the pooling mechanism can be disabled. /// public static bool IsEnabled { get { return _isEnabled; } set { _isEnabled = value; // When set to non-enabled remove all stored entries if (!_isEnabled) Clear(); } } private static volatile bool _isEnabled = true; /// /// Buffer entries that released back to the pool and older than this value are moved when next maintenance is triggered. /// public static TimeSpan RemoveOlderThan = TimeSpan.FromSeconds(10); /// /// How often pool maintenance must run. /// public static TimeSpan RunMaintenanceEvery = TimeSpan.FromSeconds(5); private static DateTime lastMaintenance = DateTime.MinValue; private readonly static ReaderWriterLockSlim rwLock = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion); struct BuilderShelf { public StringBuilder builder; public DateTime released; public BuilderShelf(StringBuilder sb) { this.builder = sb; this.released = DateTime.Now; } } private static List pooledBuilders = new List(); public static StringBuilder Get(int lengthHint) { if (!_isEnabled) return new StringBuilder(lengthHint); using (new WriteLock(rwLock)) { for (int i = pooledBuilders.Count - 1; i >= 0; i--) { BuilderShelf shelf = pooledBuilders[i]; if (shelf.builder.Capacity >= lengthHint) { pooledBuilders.RemoveAt(i); return shelf.builder; } } // no builder found with lengthHint, take the first available if (pooledBuilders.Count > 0) { BuilderShelf shelf = pooledBuilders[pooledBuilders.Count - 1]; pooledBuilders.RemoveAt(pooledBuilders.Count - 1); return shelf.builder; } } return new StringBuilder(lengthHint); } public static void Release(StringBuilder builder) { if (builder == null) return; if (!_isEnabled) return; builder.Clear(); using (new WriteLock(rwLock)) pooledBuilders.Add(new BuilderShelf(builder)); } public static string ReleaseAndGrab(StringBuilder builder) { if (builder == null) return null; var result = builder.ToString(); if (!_isEnabled) return result; builder.Clear(); using (new WriteLock(rwLock)) pooledBuilders.Add(new BuilderShelf(builder)); return result; } internal static void Maintain() { DateTime now = DateTime.Now; if (!_isEnabled || lastMaintenance + RunMaintenanceEvery > now) return; lastMaintenance = now; DateTime olderThan = now - RemoveOlderThan; using (new WriteLock(rwLock)) { for (int i = 0; i < pooledBuilders.Count; i++) { BuilderShelf shelf = pooledBuilders[i]; if (shelf.released < olderThan) pooledBuilders.RemoveAt(i--); } } } public static void Clear() { using (new WriteLock(rwLock)) pooledBuilders.Clear(); } } }