// Copyright (C) 2010 OfficeSIP Communications
// This source is subject to the GNU General Public License.
// Please see Notice.txt for details.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
namespace SocketServers
{
static class ByteArraySegmentHelpers
{
public static bool IsValid(this ArraySegment<byte> segment)
{
return segment.Array != null && segment.Offset >= 0 && segment.Count > 0;
}
public static bool IsInvalid(this ArraySegment<byte> segment)
{
return segment.Array == null || segment.Offset < 0 || segment.Count <= 0;
}
}
public class BufferManager1
{
private InternalBufferManager[] buffers;
private SafeDictionary<byte[], int> buffersIndexes;
private int maxIndex;
private int currentIndex;
private const int segments = 128;
private const int segmentSize = 8192;
public BufferManager1()
{
buffers =
new InternalBufferManager
[2000];
buffersIndexes =
new SafeDictionary<byte
[], int>
();
buffers
[0] =
new InternalBufferManager
(segments, segmentSize
);
currentIndex = 0;
maxIndex = 0;
}
public void Allocate(IList<ArraySegment<byte>> list, int size)
{
int index = currentIndex;
for (; ; )
{
do
{
int segmentsCount = (size + segmentSize - 1) / segmentSize;
if (buffers[index].FreeCount > segmentsCount)
{
var segment = buffers[index].Allocate(size);
if (segment.IsValid())
{
list.Add(segment);
size -= segment.Count;
}
if (currentIndex != index &&
buffers[index].FreeCount > buffers[currentIndex].FreeCount)
{
Interlocked.Exchange(ref currentIndex, index);
}
if (size == 0)
return;
}
index = (index < maxIndex) ? index + 1 : 0;
}
while (index != currentIndex);
index = AddInternalBuffer();
}
}
public void Free(IList<ArraySegment<byte>> list)
{
int length = list.Count;
for (int i = 0; i < length; i++)
Free(list[i]);
}
public void Free(ArraySegment<byte> segment)
{
buffers[buffersIndexes.GetValue(segment.Array)].Free(segment);
}
public void AddRef(ArraySegment<byte> segment)
{
buffers[buffersIndexes.GetValue(segment.Array)].AddRef(segment);
}
public int SegmentSize
{
get { return segmentSize; }
}
private int AddInternalBuffer()
{
var buffer =
new InternalBufferManager
(segments, segmentSize
);
for (; ; )
{
int index = maxIndex + 1;
if (Interlocked.CompareExchange(ref buffers[index], buffer, null) == null)
{
buffersIndexes.Add(buffer.Buffer, index);
return Interlocked.Increment(ref maxIndex);
}
}
}
class InternalBufferManager
{
private byte[] _buffer;
private int[] _lockCounters;
private int _freeCount;
private int _segmentSize;
private int _segments;
public InternalBufferManager(int segments, int segmentSize)
{
_segmentSize = segmentSize;
_buffer =
new byte[segments * segmentSize
];
_lockCounters =
new int[segments
];
_freeCount = segments;
_segments = segments;
}
public ArraySegment<byte> Allocate(int size)
{
int startIndex = 0;
while (_freeCount > 0)
{
if (Interlocked.CompareExchange(ref _lockCounters[startIndex], 1, 0) == 0)
{
Interlocked.Decrement(ref _freeCount);
int allocatedSize = 0;
int endIndex = startIndex + 1;
while (size > allocatedSize && _freeCount > 0 && endIndex < _segments)
{
if (Interlocked.CompareExchange(ref _lockCounters[endIndex], 1, 0) != 0)
break;
Interlocked.Decrement(ref _freeCount);
endIndex += 1;
allocatedSize += _segmentSize;
}
return new ArraySegment<byte>
(_buffer,
(endIndex - startIndex
) * _segmentSize,
(size < allocatedSize) ? size : allocatedSize);
}
startIndex = (startIndex + 1) % _segments;
}
return new ArraySegment<byte>
();
}
public void Free(ArraySegment<byte> segment)
{
int startIndex = GetSegmentIndex(segment.Offset);
int endIndex = GetSegmentIndex(segment.Offset + segment.Count - 1);
for (; startIndex < endIndex; startIndex++)
{
switch (Interlocked.Decrement(ref _lockCounters[startIndex]))
{
case 0:
Interlocked.Increment(ref _freeCount);
break;
#if DEBUG
case -1:
throw new InvalidOperationException
("Buffer segment was freed before.");
#endif
}
}
}
public void AddRef(ArraySegment<byte> segment)
{
int startIndex = GetSegmentIndex(segment.Offset);
int endIndex = GetSegmentIndex(segment.Offset + segment.Count - 1);
for (; startIndex < endIndex; startIndex++)
{
#if DEBUG
if (_lockCounters[startIndex] == 0)
throw new InvalidOperationException
("Buffer segment was not allocated yet.");
#endif
Interlocked.Increment(ref _lockCounters[startIndex]);
}
}
public int FreeCount
{
get { return _freeCount; }
}
public byte[] Buffer
{
get { return _buffer; }
}
private int GetSegmentIndex(int offset)
{
return offset / _segmentSize;
}
}
}
#region List1
class List1<T>
: IList<T>
{
private T item;
private Enumerator1 enumerator;
public List1(T item)
{
this.item = item;
}
void ICollection<T>.Add(T item)
{
}
void ICollection<T>.Clear()
{
}
bool ICollection<T>.Contains(T item)
{
return false;
}
void ICollection<T>.CopyTo(T[] array, int arrayIndex)
{
array[arrayIndex] = item;
}
bool ICollection<T>.Remove(T item)
{
return false;
}
int ICollection<T>.Count
{
get { return 1; }
}
bool ICollection<T>.IsReadOnly
{
get { return true; }
}
int IList<T>.IndexOf(T item)
{
return -1;
}
void IList<T>.Insert(int index, T item)
{
}
void IList<T>.RemoveAt(int index)
{
}
T IList<T>.this[int index]
{
get { return item; }
set { }
}
IEnumerator IEnumerable.GetEnumerator()
{
if (enumerator == null)
enumerator =
new Enumerator1
(this);
return enumerator;
}
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
if (enumerator == null)
enumerator =
new Enumerator1
(this);
return enumerator;
}
class Enumerator1
: IEnumerator<T>
{
List1<T> list1;
public Enumerator1(List1<T> list1)
{
this.list1 = list1;
}
public void Reset()
{
}
public bool MoveNext()
{
return false;
}
public Object Current
{
get { return list1.item; }
}
T IEnumerator<T>.Current
{
get { return list1.item; }
}
void IDisposable.Dispose()
{
}
}
}
#endregion
}