1 //------------------------------------------------------------------------------
2 // <copyright file="BufferAllocator.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 //------------------------------------------------------------------------------
8 * Buffer Allocators with recycling
10 * Copyright (c) 1999 Microsoft Corporation
12 namespace System.Web {
14 using System.Collections;
15 using System.Collections.Generic;
17 using System.Globalization;
19 using System.Web.Util;
21 //////////////////////////////////////////////////////////////////////////////
22 // Generic buffer recycling
24 internal interface IBufferAllocator {
26 void ReuseBuffer(object buffer);
27 void ReleaseAllBuffers();
28 int BufferSize { get; }
31 internal interface IBufferAllocator<T> : IBufferAllocator {
33 T[] GetBuffer(int minSize);
34 void ReuseBuffer(T[] buffer);
37 internal interface IAllocatorProvider {
38 IBufferAllocator<char> CharBufferAllocator { get; }
39 IBufferAllocator<int> IntBufferAllocator { get; }
40 IBufferAllocator<IntPtr> IntPtrBufferAllocator { get; }
46 * Base class for allocator doing buffer recycling
48 internal abstract class BufferAllocator : IBufferAllocator {
51 private Stack _buffers;
53 private static int s_ProcsFudgeFactor;
55 static BufferAllocator() {
56 s_ProcsFudgeFactor = SystemInfo.GetNumProcessCPUs();
57 if (s_ProcsFudgeFactor < 1)
58 s_ProcsFudgeFactor = 1;
60 if (s_ProcsFudgeFactor > 4)
61 s_ProcsFudgeFactor = 4;
65 internal BufferAllocator(int maxFree) {
66 _buffers = new Stack();
68 _maxFree = maxFree * s_ProcsFudgeFactor;
71 public void ReleaseAllBuffers() {
80 public object GetBuffer() {
86 buffer = _buffers.Pop();
93 buffer = AllocBuffer();
98 public void ReuseBuffer(object buffer) {
99 if (_numFree < _maxFree) {
101 if (_numFree < _maxFree) {
102 _buffers.Push(buffer);
110 * To be implemented by a derived class
112 abstract protected Object AllocBuffer();
113 abstract public int BufferSize { get; }
117 * Concrete allocator class for ubyte[] buffer recycling
119 internal class UbyteBufferAllocator : BufferAllocator {
120 private int _bufferSize;
122 internal UbyteBufferAllocator(int bufferSize, int maxFree) : base(maxFree) {
123 _bufferSize = bufferSize;
126 protected override Object AllocBuffer() {
127 return new byte[_bufferSize];
130 public override int BufferSize {
138 * Concrete allocator class for char[] buffer recycling
140 internal class CharBufferAllocator : BufferAllocator {
141 private int _bufferSize;
143 internal CharBufferAllocator(int bufferSize, int maxFree)
146 _bufferSize = bufferSize;
149 protected override Object AllocBuffer() {
150 return new char[_bufferSize];
153 public override int BufferSize {
161 * Concrete allocator class for int[] buffer recycling
163 internal class IntegerArrayAllocator : BufferAllocator {
164 private int _arraySize;
166 internal IntegerArrayAllocator(int arraySize, int maxFree)
169 _arraySize = arraySize;
172 protected override Object AllocBuffer() {
173 return new int[_arraySize];
176 public override int BufferSize {
184 * Concrete allocator class for IntPtr[] buffer recycling
186 internal class IntPtrArrayAllocator : BufferAllocator {
187 private int _arraySize;
189 internal IntPtrArrayAllocator(int arraySize, int maxFree)
192 _arraySize = arraySize;
195 protected override Object AllocBuffer() {
196 return new IntPtr[_arraySize];
199 public override int BufferSize {
209 * Simple Buffer Allocator - Reusable buffers pool
210 * Thread UNSAFE! Lock free. Caller must guarantee non-concurent access.
211 * Use as member of already pooled instances (like HttpApplication) that prohibit concurent access to avoid taking locks
213 internal class SimpleBufferAllocator<T> : IBufferAllocator<T> {
214 private Stack<T[]> _buffers;
215 private readonly int _bufferSize;
217 public SimpleBufferAllocator(int bufferSize) {
218 if (bufferSize <= 0) {
219 throw new ArgumentOutOfRangeException("bufferSize");
222 _buffers = new Stack<T[]>();
223 _bufferSize = bufferSize;
226 public T[] GetBuffer() {
227 return GetBufferImpl();
230 public T[] GetBuffer(int minSize) {
232 throw new ArgumentOutOfRangeException("minSize");
237 if (minSize <= BufferSize) {
239 buffer = GetBufferImpl();
242 // Allocate a new buffer. It will not be reused later
243 buffer = AllocBuffer(minSize);
249 object IBufferAllocator.GetBuffer() {
250 return GetBufferImpl();
253 public void ReuseBuffer(T[] buffer) {
254 ReuseBufferImpl(buffer);
257 void IBufferAllocator.ReuseBuffer(object buffer) {
258 ReuseBufferImpl((T[]) buffer);
261 public void ReleaseAllBuffers() {
265 public int BufferSize {
271 private T[] GetBufferImpl() {
274 if (_buffers.Count > 0) {
275 // Get an exisitng buffer
276 buffer = _buffers.Pop();
279 // Create a new buffer
280 buffer = AllocBuffer(BufferSize);
286 private void ReuseBufferImpl(T[] buffer) {
287 // Accept back only buffers that match the orirignal buffer size
288 if (buffer != null && buffer.Length == BufferSize) {
289 _buffers.Push(buffer);
293 private static T[] AllocBuffer(int size) {
300 * Adapter to convert IBufferAllocator to generic IBufferAllocator<>
302 class BufferAllocatorWrapper<T> : IBufferAllocator<T> {
303 private IBufferAllocator _allocator;
305 public BufferAllocatorWrapper(IBufferAllocator allocator) {
306 Debug.Assert(allocator != null);
308 _allocator = allocator;
311 public T[] GetBuffer() {
312 return (T[])_allocator.GetBuffer();
315 public T[] GetBuffer(int minSize) {
317 throw new ArgumentOutOfRangeException("minSize");
322 if (minSize <= BufferSize) {
323 // Get from the allocator
324 buffer = (T[])_allocator.GetBuffer();
327 // Allocate a new buffer. It will not be reused later
328 buffer = new T[minSize];
334 public void ReuseBuffer(T[] buffer) {
335 // Accept back only buffers that match the orirignal buffer size
336 if (buffer != null && buffer.Length == BufferSize) {
337 _allocator.ReuseBuffer(buffer);
341 object IBufferAllocator.GetBuffer() {
342 return _allocator.GetBuffer();
345 void IBufferAllocator.ReuseBuffer(object buffer) {
346 ReuseBuffer((T[])buffer);
349 public void ReleaseAllBuffers() {
350 _allocator.ReleaseAllBuffers();
353 public int BufferSize {
355 return _allocator.BufferSize;
362 * Provider for different buffer allocators
364 internal class AllocatorProvider : IAllocatorProvider {
365 private IBufferAllocator<char> _charAllocator = null;
366 private IBufferAllocator<int> _intAllocator = null;
367 private IBufferAllocator<IntPtr> _intPtrAllocator = null;
369 public IBufferAllocator<char> CharBufferAllocator {
371 return _charAllocator;
376 throw new ArgumentNullException("value");
379 _charAllocator = value;
383 public IBufferAllocator<int> IntBufferAllocator {
385 return _intAllocator;
390 throw new ArgumentNullException("value");
393 _intAllocator = value;
397 public IBufferAllocator<IntPtr> IntPtrBufferAllocator {
399 return _intPtrAllocator;
404 throw new ArgumentNullException("value");
407 _intPtrAllocator = value;
411 public void TrimMemory() {
412 if (_charAllocator != null) {
413 _charAllocator.ReleaseAllBuffers();
416 if (_intAllocator != null) {
417 _intAllocator.ReleaseAllBuffers();
420 if (_intPtrAllocator != null) {
421 _intPtrAllocator.ReleaseAllBuffers();