Replace whitespaces to 8-spaces tabs
[mono.git] / mcs / class / referencesource / System.Web / BufferAllocator.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="BufferAllocator.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>                                                                
5 //------------------------------------------------------------------------------
6
7 /*
8  * Buffer Allocators with recycling
9  * 
10  * Copyright (c) 1999 Microsoft Corporation
11  */
12 namespace System.Web {
13
14     using System.Collections;
15     using System.Collections.Generic;
16     using System.IO;
17     using System.Globalization;
18
19     using System.Web.Util;
20
21     //////////////////////////////////////////////////////////////////////////////
22     // Generic buffer recycling
23
24     internal interface IBufferAllocator {
25         object GetBuffer();
26         void ReuseBuffer(object buffer);
27         void ReleaseAllBuffers();
28         int BufferSize { get; }
29     }
30
31     internal interface IBufferAllocator<T> : IBufferAllocator {
32         new T[] GetBuffer();
33         T[] GetBuffer(int minSize);
34         void ReuseBuffer(T[] buffer);
35     }
36
37     internal interface IAllocatorProvider {
38         IBufferAllocator<char>  CharBufferAllocator { get; }
39         IBufferAllocator<int>   IntBufferAllocator { get; }
40         IBufferAllocator<IntPtr> IntPtrBufferAllocator { get; }
41
42         void TrimMemory();
43     }
44
45     /*
46      * Base class for allocator doing buffer recycling
47      */
48     internal abstract class BufferAllocator : IBufferAllocator {
49         private int _maxFree;
50         private int _numFree;
51         private Stack _buffers;
52
53         private static int s_ProcsFudgeFactor;
54
55         static BufferAllocator() {
56             s_ProcsFudgeFactor = SystemInfo.GetNumProcessCPUs();
57             if (s_ProcsFudgeFactor < 1) 
58                 s_ProcsFudgeFactor = 1;
59
60             if (s_ProcsFudgeFactor > 4)
61                 s_ProcsFudgeFactor = 4;
62         }
63
64
65         internal BufferAllocator(int maxFree) {
66             _buffers = new Stack();
67             _numFree = 0;
68             _maxFree = maxFree * s_ProcsFudgeFactor;
69         }
70
71         public void ReleaseAllBuffers() {
72             if (_numFree > 0) {
73                 lock (this) {
74                     _buffers.Clear();
75                     _numFree = 0;
76                 }
77             }
78         }
79
80         public object GetBuffer() {
81             Object buffer = null;
82
83             if (_numFree > 0) {
84                 lock(this) {
85                     if (_numFree > 0) {
86                         buffer = _buffers.Pop();
87                         _numFree--;
88                     }
89                 }
90             }
91
92             if (buffer == null)
93                 buffer = AllocBuffer();
94
95             return buffer;
96         }
97
98         public void ReuseBuffer(object buffer) {
99             if (_numFree < _maxFree) {
100                 lock(this) {
101                     if (_numFree < _maxFree) {
102                         _buffers.Push(buffer);
103                         _numFree++;
104                     }
105                 }
106             }
107         }
108
109         /*
110          * To be implemented by a derived class
111          */
112         abstract protected Object AllocBuffer();
113         abstract public int BufferSize { get; }
114     }
115
116     /*
117      * Concrete allocator class for ubyte[] buffer recycling
118      */
119     internal class UbyteBufferAllocator : BufferAllocator {
120         private int _bufferSize;
121
122         internal UbyteBufferAllocator(int bufferSize, int maxFree) : base(maxFree) {
123             _bufferSize = bufferSize;
124         }
125
126         protected override Object AllocBuffer() {
127             return new byte[_bufferSize];
128         }
129
130         public override int BufferSize { 
131             get {
132                 return _bufferSize;
133             } 
134         }
135     }
136
137     /*
138      * Concrete allocator class for char[] buffer recycling
139      */
140     internal class CharBufferAllocator : BufferAllocator {
141         private int _bufferSize;
142
143         internal CharBufferAllocator(int bufferSize, int maxFree)
144
145         : base(maxFree) {
146             _bufferSize = bufferSize;
147         }
148
149         protected override Object AllocBuffer() {
150             return new char[_bufferSize];
151         }
152
153         public override int BufferSize {
154             get {
155                 return _bufferSize;
156             }
157         }
158     }
159
160     /*
161      * Concrete allocator class for int[] buffer recycling
162      */
163     internal class IntegerArrayAllocator : BufferAllocator {
164         private int _arraySize;
165
166         internal IntegerArrayAllocator(int arraySize, int maxFree)
167
168         : base(maxFree) {
169             _arraySize = arraySize;
170         }
171
172         protected override Object AllocBuffer() {
173             return new int[_arraySize];
174         }
175
176         public override int BufferSize {
177             get {
178                 return _arraySize;
179             }
180         }
181     }
182
183     /*
184      * Concrete allocator class for IntPtr[] buffer recycling
185      */
186     internal class IntPtrArrayAllocator : BufferAllocator {
187         private int _arraySize;
188
189         internal IntPtrArrayAllocator(int arraySize, int maxFree)
190
191         : base(maxFree) {
192             _arraySize = arraySize;
193         }
194
195         protected override Object AllocBuffer() {
196             return new IntPtr[_arraySize];
197         }
198
199         public override int BufferSize {
200             get {
201                 return _arraySize;
202             }
203         }
204     }
205
206
207
208     /*
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
212      */
213     internal class SimpleBufferAllocator<T> : IBufferAllocator<T> {
214         private Stack<T[]>   _buffers;
215         private readonly int _bufferSize;
216
217         public SimpleBufferAllocator(int bufferSize) {
218             if (bufferSize <= 0) {
219                 throw new ArgumentOutOfRangeException("bufferSize");
220             }
221
222             _buffers = new Stack<T[]>();
223             _bufferSize = bufferSize;
224         }
225
226         public T[] GetBuffer() {
227             return GetBufferImpl();
228         }
229
230         public T[] GetBuffer(int minSize) {
231             if (minSize < 0) {
232                 throw new ArgumentOutOfRangeException("minSize");
233             }
234
235             T[] buffer = null;
236
237             if (minSize <= BufferSize) {
238                 // Get from the pool
239                 buffer = GetBufferImpl();
240             }
241             else {
242                 // Allocate a new buffer. It will not be reused later
243                 buffer = AllocBuffer(minSize);
244             }
245
246             return buffer;
247         }
248
249         object IBufferAllocator.GetBuffer() {
250             return GetBufferImpl();
251         }
252
253         public void ReuseBuffer(T[] buffer) {
254             ReuseBufferImpl(buffer);
255         }
256
257         void IBufferAllocator.ReuseBuffer(object buffer) {
258             ReuseBufferImpl((T[]) buffer);
259         }
260
261         public void ReleaseAllBuffers() {
262             _buffers.Clear();
263         }
264
265         public int BufferSize {
266             get {
267                 return _bufferSize;
268             }
269         }
270
271         private T[] GetBufferImpl() {
272             T[] buffer = null;
273
274             if (_buffers.Count > 0) {
275                 // Get an exisitng buffer
276                 buffer = _buffers.Pop();
277             }
278             else {
279                 // Create a new buffer
280                 buffer = AllocBuffer(BufferSize);
281             }
282
283             return buffer;
284         }
285
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);
290             }
291         }
292
293         private static T[] AllocBuffer(int size) {
294             return new T[size];
295         }
296     }
297
298
299     /*
300      * Adapter to convert IBufferAllocator to generic IBufferAllocator<>
301      */
302     class BufferAllocatorWrapper<T> : IBufferAllocator<T> {
303         private IBufferAllocator _allocator;
304
305         public BufferAllocatorWrapper(IBufferAllocator allocator) {
306             Debug.Assert(allocator != null);
307
308             _allocator = allocator;
309         }
310
311         public T[] GetBuffer() {
312             return (T[])_allocator.GetBuffer();
313         }
314
315         public T[] GetBuffer(int minSize) {
316             if (minSize < 0) {
317                 throw new ArgumentOutOfRangeException("minSize");
318             }
319
320             T[] buffer = null;
321
322             if (minSize <= BufferSize) {
323                 // Get from the allocator
324                 buffer = (T[])_allocator.GetBuffer();
325             }
326             else {
327                 // Allocate a new buffer. It will not be reused later
328                 buffer = new T[minSize];
329             }
330
331             return buffer;
332         }
333
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);
338             }
339         }
340
341         object IBufferAllocator.GetBuffer() {
342             return _allocator.GetBuffer();
343         }
344
345         void IBufferAllocator.ReuseBuffer(object buffer) {
346             ReuseBuffer((T[])buffer);
347         }
348
349         public void ReleaseAllBuffers() {
350             _allocator.ReleaseAllBuffers();
351         }
352
353         public int BufferSize {
354             get {
355                 return _allocator.BufferSize;
356             }
357         }
358     }
359
360
361     /*
362      * Provider for different buffer allocators
363      */
364     internal class AllocatorProvider : IAllocatorProvider {
365         private IBufferAllocator<char>   _charAllocator = null;
366         private IBufferAllocator<int> _intAllocator = null;
367         private IBufferAllocator<IntPtr> _intPtrAllocator = null;
368
369         public IBufferAllocator<char> CharBufferAllocator {
370             get {
371                 return _charAllocator;
372             }
373
374             set {
375                 if (value == null) {
376                     throw new ArgumentNullException("value");
377                 }
378
379                 _charAllocator = value;
380             }
381         }
382
383         public  IBufferAllocator<int> IntBufferAllocator {
384             get {
385                 return _intAllocator;
386             }
387
388             set {
389                 if (value == null) {
390                     throw new ArgumentNullException("value");
391                 }
392
393                 _intAllocator = value;
394             }
395         }
396
397         public IBufferAllocator<IntPtr> IntPtrBufferAllocator {
398             get {
399                 return _intPtrAllocator;
400             }
401
402             set {
403                 if (value == null) {
404                     throw new ArgumentNullException("value");
405                 }
406
407                 _intPtrAllocator = value;
408             }
409         }
410
411         public void TrimMemory() {
412             if (_charAllocator != null) {
413                 _charAllocator.ReleaseAllBuffers();
414             }
415
416             if (_intAllocator != null) {
417                 _intAllocator.ReleaseAllBuffers();
418             }
419
420             if (_intPtrAllocator != null) {
421                 _intPtrAllocator.ReleaseAllBuffers();
422             }
423         }
424     }
425 }