| File: MS\Internal\FontCache\BufferCache.cs | Web Access |
| Project: src\wpf\src\Microsoft.DotNet.Wpf\src\PresentationCore\PresentationCore.csproj (PresentationCore) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // // // // Description: BufferCache class implementation. // using System.Threading; using MS.Internal.Text.TextInterface; namespace MS.Internal.FontCache { /// <summary> /// A static, thread safe array cache used to minimize heap allocations. /// </summary> /// <remarks> /// Cached arrays are not zero initialized, and they may be larger than /// the requested number of elements. /// </remarks> internal static class BufferCache { //------------------------------------------------------ // // Internal Methods // //------------------------------------------------------ #region Internal Methods /// <summary> /// Attempts to release all allocated memory. Has no effect if the cache /// is locked by another thread. /// </summary> internal static void Reset() { if (Interlocked.Increment(ref _mutex) == 1) { _buffers = null; } Interlocked.Decrement(ref _mutex); } /// <summary> /// Returns a GlyphMetrics[]. /// </summary> /// <param name="length"> /// Minimum number of elements in the array. /// </param> internal static GlyphMetrics[] GetGlyphMetrics(int length) { GlyphMetrics[] glyphMetrics = (GlyphMetrics[])GetBuffer(length, GlyphMetricsIndex); if (glyphMetrics == null) { glyphMetrics = new GlyphMetrics[length]; } return glyphMetrics; } /// <summary> /// Releases a previously allocated GlyphMetrics[], possibly adding it /// to the cache. /// </summary> /// <remarks> /// It is not strictly necessary to call this method after receiving an /// array. The penalty is the performance hit of doing a heap allocation /// on the next request if this method is not called. /// </remarks> internal static void ReleaseGlyphMetrics(GlyphMetrics[] glyphMetrics) { ReleaseBuffer(glyphMetrics, GlyphMetricsIndex); } /// <summary> /// Returns a ushort[]. /// </summary> /// <param name="length"> /// Minimum number of elements in the array. /// </param> internal static ushort[] GetUShorts(int length) { ushort[] ushorts = (ushort[])GetBuffer(length, UShortsIndex); if (ushorts == null) { ushorts = new ushort[length]; } return ushorts; } /// <summary> /// Releases a previously allocated ushort[], possibly adding it /// to the cache. /// </summary> /// <remarks> /// It is not strictly necessary to call this method after receiving an /// array. The penalty is the performance hit of doing a heap allocation /// on the next request if this method is not called. /// </remarks> internal static void ReleaseUShorts(ushort[] ushorts) { ReleaseBuffer(ushorts, UShortsIndex); } /// <summary> /// Returns a uint[]. /// </summary> /// <param name="length"> /// Minimum number of elements in the array. /// </param> internal static uint[] GetUInts(int length) { uint[] uints = (uint[])GetBuffer(length, UIntsIndex); if (uints == null) { uints = new uint[length]; } return uints; } /// <summary> /// Releases a previously allocated uint[], possibly adding it /// to the cache. /// </summary> /// <remarks> /// It is not strictly necessary to call this method after receiving an /// array. The penalty is the performance hit of doing a heap allocation /// on the next request if this method is not called. /// </remarks> internal static void ReleaseUInts(uint[] uints) { ReleaseBuffer(uints, UIntsIndex); } #endregion Internal Methods //------------------------------------------------------ // // Private Methods // //------------------------------------------------------ #region Private Methods /// <summary> /// Searches for an array in the cache. /// </summary> /// <param name="length"> /// Minimum number of elements in the array. /// </param> /// <param name="index"> /// Specifies the type of array. /// </param> /// <returns> /// A matching array if present, otherwise null. /// </returns> private static Array GetBuffer(int length, int index) { Array buffer = null; if (Interlocked.Increment(ref _mutex) == 1) { if (_buffers != null && _buffers[index] != null && length <= _buffers[index].Length) { buffer = _buffers[index]; _buffers[index] = null; } } Interlocked.Decrement(ref _mutex); return buffer; } /// <summary> /// Takes ownership of an array. /// </summary> /// <param name="buffer"> /// The array. May be null. /// </param> /// <param name="index"> /// Specifies the type of array. /// </param> private static void ReleaseBuffer(Array buffer, int index) { if (buffer != null) { if (Interlocked.Increment(ref _mutex) == 1) { if (_buffers == null) { _buffers = new Array[BuffersLength]; } if (_buffers[index] == null || (_buffers[index].Length < buffer.Length && buffer.Length <= MaxBufferLength)) { _buffers[index] = buffer; } } Interlocked.Decrement(ref _mutex); } } #endregion Private Methods //------------------------------------------------------ // // Private Fields // //------------------------------------------------------ #region Private Fields // Max number of elements in any cached array. If a request if made for a larger array // it will always be allocated from the heap. private const int MaxBufferLength = 1024; // Indices in _buffers for each supported type. private const int GlyphMetricsIndex = 0; private const int UIntsIndex = 1; private const int UShortsIndex = 2; private const int BuffersLength = 3; // Guards access to _buffers. private static long _mutex; // Array of cached arrays, one bucker per supported type. // Currently, we cache just one array per type. A more general cache would hold N byte arrays. // However, we don't currently have any scenarios that hold more than one array of the same type // or more than two arrays of different types at the same time, so it is difficult to justify // making the implementation more complex. ComputeTypographyAvailabilities could benefit from // a more general cache (UnicodeRange.GetFullRange could use a cached array), but the savings // in profiled scenarios are small, ~16k for MSNBaml.exe. If we find a more compelling // scenario a change might be worthwhile. private static Array[] _buffers; #endregion Private Fields } }