/// <summary>
/// 指针的操作
/// </summary>
internal class PointerHelper
{
private byte* _pBuffer;
private bool _disposed;
private GCHandle _pinnedGCHandle;
private bool _needToFreeGCHandle;
private int _capacity;
/// <summary>
///
/// </summary>
public byte[] Data { get; private set; }
/// <summary>
/// Attach a view to a byte[] for providing direct access
/// </summary>
/// <param name="buffer">buffer to which the view is attached.</param>
public PointerHelper(byte[] buffer)
{
if (buffer == null) throw new ArgumentNullException("buffer");
this.Data = buffer;
// pin the buffer so it does not get moved around by GC, this is required since we use pointers
_pinnedGCHandle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
_needToFreeGCHandle = true;
_pBuffer = (byte*)_pinnedGCHandle.AddrOfPinnedObject().ToPointer();
_capacity = buffer.Length;
}
/// <summary>
/// Capacity of the underlying buffer
/// </summary>
public int Capacity
{
get { return _capacity; }
}
/// <summary>
/// Gets the <see cref="byte"/> value at a given index.
/// </summary>
/// <param name="index">index in bytes from which to get.</param>
/// <returns>the value at a given index.</returns>
public char CharGet(int index)
{
return (char)*(_pBuffer + index);
}
/// <summary>
/// Writes a <see cref="byte"/> value to a given index.
/// </summary>
/// <param name="index">index in bytes for where to put.</param>
/// <param name="value">value to be written</param>
public void CharPut(int index, char value)
{
*(_pBuffer + index) = (byte)value;
}
/// <summary>
/// Gets the <see cref="sbyte"/> value at a given index.
/// </summary>
/// <param name="index"> index in bytes from which to get.</param>
/// <returns>the value at a given index.</returns>
public sbyte Int8Get(int index)
{
return *(sbyte*)(_pBuffer + index);
}
/// <summary>
/// Writes a <see cref="sbyte"/> value to a given index.
/// </summary>
/// <param name="index">index in bytes for where to put.</param>
/// <param name="value">value to be written</param>
public void Int8Put(int index, sbyte value)
{
*(sbyte*)(_pBuffer + index) = value;
}
/// <summary>
/// Gets the <see cref="byte"/> value at a given index.
/// </summary>
/// <param name="index"> index in bytes from which to get.</param>
/// <returns>the value at a given index.</returns>
public byte UInt8Get(int index)
{
return *(_pBuffer + index);
}
/// <summary>
/// Writes a <see cref="byte"/> value to a given index.
/// </summary>
/// <param name="index">index in bytes for where to put.</param>
/// <param name="value">value to be written</param>
public void UInt8Put(int index, byte value)
{
*(_pBuffer + index) = value;
}
/// <summary>
///
/// </summary>
/// <param name="index"></param>
/// <returns></returns>
public bool BoolGet(int index)
{
return *(_pBuffer + index) == 1;
}
/// <summary>
///
/// </summary>
/// <param name="index"></param>
/// <param name="value"></param>
public void BoolPut(int index, bool value)
{
*(_pBuffer + index) = (byte)(value ? 1 : 0);
}
/// <summary>
/// Gets the <see cref="short"/> value at a given index.
/// </summary>
/// <param name="index"> index in bytes from which to get.</param>
/// <returns>the value at a given index.</returns>
public short Int16Get(int index)
{
return *(short*)(_pBuffer + index);
}
/// <summary>
/// Writes a <see cref="short"/> value to a given index.
/// </summary>
/// <param name="index">index in bytes for where to put.</param>
/// <param name="value">value to be written</param>
public void Int16Put(int index, short value)
{
*(short*)(_pBuffer + index) = value;
}
/// <summary>
/// Gets the <see cref="int"/> value at a given index.
/// </summary>
/// <param name="index"> index in bytes from which to get.</param>
/// <returns>the value at a given index.</returns>
public int Int32Get(int index)
{
return *(int*)(_pBuffer + index);
}
/// <summary>
/// Writes a <see cref="int"/> value to a given index.
/// </summary>
/// <param name="index">index in bytes for where to put.</param>
/// <param name="value">value to be written</param>
public void Int32Put(int index, int value)
{
*(int*)(_pBuffer + index) = value;
}
/// <summary>
/// Gets the <see cref="long"/> value at a given index.
/// </summary>
/// <param name="index"> index in bytes from which to get.</param>
/// <returns>the value at a given index.</returns>
public long Int64Get(int index)
{
return *(long*)(_pBuffer + index);
}
/// <summary>
/// Writes a <see cref="long"/> value to a given index.
/// </summary>
/// <param name="index">index in bytes for where to put.</param>
/// <param name="value">value to be written</param>
public void Int64Put(int index, long value)
{
*(long*)(_pBuffer + index) = value;
}
/// <summary>
/// Gets the <see cref="ushort"/> value at a given index.
/// </summary>
/// <param name="index"> index in bytes from which to get.</param>
/// <returns>the value at a given index.</returns>
public ushort UInt16Get(int index)
{
return *(ushort*)(_pBuffer + index);
}
/// <summary>
/// Writes a <see cref="ushort"/> value to a given index.
/// </summary>
/// <param name="index">index in bytes for where to put.</param>
/// <param name="value">value to be written</param>
public void UInt16Put(int index, ushort value)
{
*(ushort*)(_pBuffer + index) = value;
}
/// <summary>
/// Gets the <see cref="uint"/> value at a given index.
/// </summary>
/// <param name="index"> index in bytes from which to get.</param>
/// <returns>the value at a given index.</returns>
public uint UInt32Get(int index)
{
return *(uint*)(_pBuffer + index);
}
/// <summary>
/// Writes a <see cref="uint"/> value to a given index.
/// </summary>
/// <param name="index">index in bytes for where to put.</param>
/// <param name="value">value to be written</param>
public void UInt32Put(int index, uint value)
{
*(uint*)(_pBuffer + index) = value;
}
/// <summary>
/// Gets the <see cref="ulong"/> value at a given index.
/// </summary>
/// <param name="index"> index in bytes from which to get.</param>
/// <returns>the value at a given index.</returns>
public ulong UInt64Get(int index)
{
return *(ulong*)(_pBuffer + index);
}
/// <summary>
/// Writes a <see cref="ulong"/> value to a given index.
/// </summary>
/// <param name="index">index in bytes for where to put.</param>
/// <param name="value">value to be written</param>
public void UInt64Put(int index, ulong value)
{
*(ulong*)(_pBuffer + index) = value;
}
/// <summary>
/// Gets the <see cref="float"/> value at a given index.
/// </summary>
/// <param name="index"> index in bytes from which to get.</param>
/// <returns>the value at a given index.</returns>
public float FloatGet(int index)
{
return *(float*)(_pBuffer + index);
}
/// <summary>
/// Writes a <see cref="float"/> value to a given index.
/// </summary>
/// <param name="index">index in bytes for where to put.</param>
/// <param name="value">value to be written</param>
public void FloatPut(int index, float value)
{
*(float*)(_pBuffer + index) = value;
}
/// <summary>
/// Gets the <see cref="double"/> value at a given index.
/// </summary>
/// <param name="index"> index in bytes from which to get.</param>
/// <returns>the value at a given index.</returns>
public double DoubleGet(int index)
{
return *(double*)(_pBuffer + index);
}
/// <summary>
/// Writes a <see cref="double"/> value to a given index.
/// </summary>
/// <param name="index">index in bytes for where to put.</param>
/// <param name="value">value to be written</param>
public void DoublePut(int index, double value)
{
*(double*)(_pBuffer + index) = value;
}
/// <summary>
/// 字符串存储为两位数字=字符串长度 + 字符串(每个字符占两个字节)
/// </summary>
/// <param name="index"></param>
/// <param name="length">chars</param>
/// <returns></returns>
public string StringGet(int index, int length)
{
int len = UInt16Get(index);
if (len <= 0) return string.Empty;
return new string((char*)(_pBuffer + index + 2), 0, len);
}
/// <summary>
/// 字符串存储为两位数字=字符串长度 + 字符串(每个字符占两个字节)
/// </summary>
/// <param name="index"></param>
/// <param name="length">chars</param>
/// <param name="value"></param>
public void StringPut(int index, int length, string value)
{
if (string.IsNullOrWhiteSpace(value))
{
UInt16Put(index, 0);
}
else
{
char[] chars = value.ToCharArray();
int len = Math.Min(length, chars.Length);
UInt16Put(index, (UInt16)len);
Marshal.Copy(chars, 0, (IntPtr)(_pBuffer + index + 2), len);
}
}
/// <summary>
///
/// </summary>
/// <param name="index"></param>
/// <param name="length"></param>
/// <returns></returns>
public byte[] BinaryGet(int index, int length)
{
byte[] dest = new byte[length];
GetBytes(index, dest, 0, length);
return dest;
}
/// <summary>
///
/// </summary>
/// <param name="index"></param>
/// <param name="length"></param>
/// <param name="src"></param>
/// <returns></returns>
public void BinaryPut(int index, int length, byte[] src)
{
SetBytes(index, src, 0, Math.Min(src.Length, length));
}
/// <summary>
///
/// </summary>
/// <param name="index"></param>
/// <param name="length"></param>
/// <param name="dest"></param>
/// <returns></returns>
public int GetBytes(int index, int length, ref byte[] dest)
{
if (dest == null) return 0;
return GetBytes(index, dest, 0, Math.Min(length, dest.Length));
}
/// <summary>
/// Copies a range of bytes from the underlying into a supplied byte array.
/// </summary>
/// <param name="index">index in the underlying buffer to start from.</param>
/// <param name="destination">array into which the bytes will be copied.</param>
/// <param name="offsetDestination">offset in the supplied buffer to start the copy</param>
/// <param name="length">length of the supplied buffer to use.</param>
/// <returns>count of bytes copied.</returns>
public int GetBytes(int index, byte[] destination, int offsetDestination, int length)
{
int count = Math.Min(length, _capacity - index);
Marshal.Copy((IntPtr)(_pBuffer + index), destination, offsetDestination, count);
return count;
}
/// <summary>
/// Writes a byte array into the underlying buffer.
/// </summary>
/// <param name="index">index in the underlying buffer to start from.</param>
/// <param name="src">source byte array to be copied to the underlying buffer.</param>
/// <param name="offset">offset in the supplied buffer to begin the copy.</param>
/// <param name="length">length of the supplied buffer to copy.</param>
/// <returns>count of bytes copied.</returns>
public int SetBytes(int index, byte[] src, int offset, int length)
{
int count = Math.Min(length, _capacity - index);
Marshal.Copy(src, offset, (IntPtr)(_pBuffer + index), count);
return count;
}
/// <summary>
///
/// </summary>
public void Reset()
{
Array.Clear(this.Data, 0, this.Data.Length);
}
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
/// <filterpriority>2</filterpriority>
public override void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
base.Dispose();
}
/// <summary>
/// Destructor for <see cref="DirectBuffer"/>
/// </summary>
~PointerHelper()
{
Dispose(false);
}
private void Dispose(bool disposing)
{
if (_disposed)
return;
FreeGCHandle();
_disposed = true;
}
private void FreeGCHandle()
{
if (_needToFreeGCHandle)
{
_pinnedGCHandle.Free();
_needToFreeGCHandle = false;
}
}
}