1 // Licensed to the .NET Foundation under one or more agreements. 2 // The .NET Foundation licenses this file to you under the MIT license. 3 // See the LICENSE file in the project root for more information. 4 5 /*============================================================ 6 ** 7 ** 8 ** Purpose: provide a cached reusable instance of stringbuilder 9 ** per thread it's an optimisation that reduces the 10 ** number of instances constructed and collected. 11 ** 12 ** Acquire - is used to get a string builder to use of a 13 ** particular size. It can be called any number of 14 ** times, if a stringbuilder is in the cache then 15 ** it will be returned and the cache emptied. 16 ** subsequent calls will return a new stringbuilder. 17 ** 18 ** A StringBuilder instance is cached in 19 ** Thread Local Storage and so there is one per thread 20 ** 21 ** Release - Place the specified builder in the cache if it is 22 ** not too big. 23 ** The stringbuilder should not be used after it has 24 ** been released. 25 ** Unbalanced Releases are perfectly acceptable. It 26 ** will merely cause the runtime to create a new 27 ** stringbuilder next time Acquire is called. 28 ** 29 ** GetStringAndRelease 30 ** - ToString() the stringbuilder, Release it to the 31 ** cache and return the resulting string 32 ** 33 ===========================================================*/ 34 35 using System.Threading; 36 37 namespace System.Text 38 { 39 internal static class StringBuilderCache 40 { 41 private const int MAX_BUILDER_SIZE = 260; 42 43 // WARNING: We allow diagnostic tools to directly inspect this member (t_cachedInstance). 44 // See https://github.com/dotnet/corert/blob/master/Documentation/design-docs/diagnostics/diagnostics-tools-contract.md for more details. 45 // Please do not change the type, the name, or the semantic usage of this member without understanding the implication for tools. 46 // Get in touch with the diagnostics team if you have questions. 47 [ThreadStatic] 48 private static StringBuilder t_cachedInstance; 49 Acquire(int capacity = StringBuilder.DefaultCapacity)50 public static StringBuilder Acquire(int capacity = StringBuilder.DefaultCapacity) 51 { 52 if (capacity <= MAX_BUILDER_SIZE) 53 { 54 StringBuilder sb = StringBuilderCache.t_cachedInstance; 55 if (sb != null) 56 { 57 // Avoid stringbuilder block fragmentation by getting a new StringBuilder 58 // when the requested size is larger than the current capacity 59 if (capacity <= sb.Capacity) 60 { 61 StringBuilderCache.t_cachedInstance = null; 62 sb.Clear(); 63 return sb; 64 } 65 } 66 } 67 return new StringBuilder(capacity); 68 } 69 Release(StringBuilder sb)70 public static void Release(StringBuilder sb) 71 { 72 if (sb.Capacity <= MAX_BUILDER_SIZE) 73 { 74 StringBuilderCache.t_cachedInstance = sb; 75 } 76 } 77 GetStringAndRelease(StringBuilder sb)78 public static string GetStringAndRelease(StringBuilder sb) 79 { 80 string result = sb.ToString(); 81 Release(sb); 82 return result; 83 } 84 } 85 } 86