// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Buffers; using System.Collections.Generic; using System.IO; namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal { /// /// A that uses pooled memory. /// public class MemoryPoolViewBufferScope : IViewBufferScope, IDisposable { public static readonly int MinimumSize = 16; private readonly ArrayPool _viewBufferPool; private readonly ArrayPool _charPool; private List _available; private List _leased; private bool _disposed; /// /// Initializes a new instance of . /// /// /// The for creating instances. /// /// /// The for creating instances. /// public MemoryPoolViewBufferScope(ArrayPool viewBufferPool, ArrayPool charPool) { _viewBufferPool = viewBufferPool; _charPool = charPool; } /// public ViewBufferValue[] GetPage(int pageSize) { if (pageSize <= 0) { throw new ArgumentOutOfRangeException(nameof(pageSize)); } if (_disposed) { throw new ObjectDisposedException(typeof(MemoryPoolViewBufferScope).FullName); } if (_leased == null) { _leased = new List(1); } ViewBufferValue[] segment = null; // Reuse pages that have been returned before going back to the memory pool. if (_available != null && _available.Count > 0) { segment = _available[_available.Count - 1]; _available.RemoveAt(_available.Count - 1); return segment; } try { segment = _viewBufferPool.Rent(Math.Max(pageSize, MinimumSize)); _leased.Add(segment); } catch when (segment != null) { _viewBufferPool.Return(segment); throw; } return segment; } /// public void ReturnSegment(ViewBufferValue[] segment) { if (segment == null) { throw new ArgumentNullException(nameof(segment)); } Array.Clear(segment, 0, segment.Length); if (_available == null) { _available = new List(); } _available.Add(segment); } /// public PagedBufferedTextWriter CreateWriter(TextWriter writer) { if (writer == null) { throw new ArgumentNullException(nameof(writer)); } return new PagedBufferedTextWriter(_charPool, writer); } /// public void Dispose() { if (!_disposed) { _disposed = true; if (_leased == null) { return; } for (var i = 0; i < _leased.Count; i++) { _viewBufferPool.Return(_leased[i], clearArray: true); } _leased.Clear(); } } } }