// 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();
}
}
}
}