You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

749 lines
24 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using HslCommunication.Core;
namespace HslCommunication.BasicFramework
{
/// <summary>
/// 一个线程安全的缓存数据块,支持批量动态修改,添加,并获取快照
/// </summary>
/// <remarks>
/// 这个类可以实现什么功能呢就是你有一个大的数组作为你的应用程序的中间数据池允许你往byte[]数组里存放指定长度的子byte[]数组,也允许从里面拿数据,
/// 这些操作都是线程安全的,当然,本类扩展了一些额外的方法支持,也可以直接赋值或获取基本的数据类型对象。
/// </remarks>
/// <example>
/// 此处举例一些数据的读写说明,可以此处的数据示例。
/// <code lang="cs" source="HslCommunication_Net45.Test\Documentation\Samples\BasicFramework\SoftBufferExample.cs" region="SoftBufferExample1" title="SoftBuffer示例" />
/// </example>
public class SoftBuffer : IDisposable
{
#region Constructor
/// <summary>
/// 使用默认的大小初始化缓存空间
/// </summary>
public SoftBuffer( )
{
buffer = new byte[capacity];
hybirdLock = new SimpleHybirdLock( );
byteTransform = new RegularByteTransform( );
}
/// <summary>
/// 使用指定的容量初始化缓存数据块
/// </summary>
/// <param name="capacity">初始化的容量</param>
public SoftBuffer(int capacity )
{
buffer = new byte[capacity];
this.capacity = capacity;
hybirdLock = new SimpleHybirdLock( );
byteTransform = new RegularByteTransform( );
}
#endregion
#region Bool Operate Support
/// <summary>
/// 设置指定的位置的数据块,如果超出,则丢弃数据
/// </summary>
/// <param name="value">bool值</param>
/// <param name="destIndex">目标存储的索引</param>
/// <exception cref="IndexOutOfRangeException"></exception>
public void SetBool( bool value, int destIndex )
{
SetBool( new bool[] { value }, destIndex );
}
/// <summary>
/// 设置指定的位置的数据块,如果超出,则丢弃数据
/// </summary>
/// <param name="value">bool数组值</param>
/// <param name="destIndex">目标存储的索引</param>
/// <exception cref="IndexOutOfRangeException"></exception>
public void SetBool( bool[] value, int destIndex )
{
if (value != null)
{
try
{
hybirdLock.Enter( );
for (int i = 0; i < value.Length; i++)
{
int byteIndex = (destIndex + i) / 8;
int offect = (destIndex + i) % 8;
if (value[i])
{
buffer[byteIndex] = (byte)(buffer[byteIndex] | getOrByte( offect ));
}
else
{
buffer[byteIndex] = (byte)(buffer[byteIndex] & getAndByte( offect ));
}
}
hybirdLock.Leave( );
}
catch
{
hybirdLock.Leave( );
throw;
}
}
}
/// <summary>
/// 获取指定的位置的bool值如果超出则引发异常
/// </summary>
/// <param name="destIndex">目标存储的索引</param>
/// <returns>获取索引位置的bool数据值</returns>
/// <exception cref="IndexOutOfRangeException"></exception>
public bool GetBool( int destIndex )
{
return GetBool( destIndex, 1 )[0];
}
/// <summary>
/// 获取指定位置的bool数组值如果超过则引发异常
/// </summary>
/// <param name="destIndex">目标存储的索引</param>
/// <param name="length">读取的数组长度</param>
/// <exception cref="IndexOutOfRangeException"></exception>
/// <returns>bool数组值</returns>
public bool[] GetBool( int destIndex, int length )
{
bool[] result = new bool[length];
try
{
hybirdLock.Enter( );
for (int i = 0; i < length; i++)
{
int byteIndex = (destIndex + i) / 8;
int offect = (destIndex + i) % 8;
result[i] = (buffer[byteIndex] & getOrByte( offect )) == getOrByte( offect );
}
hybirdLock.Leave( );
}
catch
{
hybirdLock.Leave( );
throw;
}
return result;
}
private byte getAndByte(int offect )
{
switch (offect)
{
case 0: return 0xFE;
case 1: return 0xFD;
case 2: return 0xFB;
case 3: return 0xF7;
case 4: return 0xEF;
case 5: return 0xDF;
case 6: return 0xBF;
case 7: return 0x7F;
default: return 0xFF;
}
}
private byte getOrByte( int offect )
{
switch (offect)
{
case 0: return 0x01;
case 1: return 0x02;
case 2: return 0x04;
case 3: return 0x08;
case 4: return 0x10;
case 5: return 0x20;
case 6: return 0x40;
case 7: return 0x80;
default: return 0x00;
}
}
#endregion
#region Byte Operate Support
/// <summary>
/// 设置指定的位置的数据块,如果超出,则丢弃数据
/// </summary>
/// <param name="data">数据块信息</param>
/// <param name="destIndex">目标存储的索引</param>
public void SetBytes( byte[] data, int destIndex )
{
if (destIndex < capacity && destIndex >= 0 && data != null)
{
hybirdLock.Enter( );
if ((data.Length + destIndex) > buffer.Length)
{
Array.Copy( data, 0, buffer, destIndex, (buffer.Length - destIndex) );
}
else
{
data.CopyTo( buffer, destIndex );
}
hybirdLock.Leave( );
}
}
/// <summary>
/// 设置指定的位置的数据块,如果超出,则丢弃数据
/// </summary>
/// <param name="data">数据块信息</param>
/// <param name="destIndex">目标存储的索引</param>
/// <param name="length">准备拷贝的数据长度</param>
public void SetBytes( byte[] data, int destIndex, int length )
{
if (destIndex < capacity && destIndex >= 0 && data != null)
{
if (length > data.Length) length = data.Length;
hybirdLock.Enter( );
if ((length + destIndex) > buffer.Length)
{
Array.Copy( data, 0, buffer, destIndex, (buffer.Length - destIndex) );
}
else
{
Array.Copy( data, 0, buffer, destIndex, length );
}
hybirdLock.Leave( );
}
}
/// <summary>
/// 设置指定的位置的数据块,如果超出,则丢弃数据
/// </summary>
/// <param name="data">数据块信息</param>
/// <param name="sourceIndex">Data中的起始位置</param>
/// <param name="destIndex">目标存储的索引</param>
/// <param name="length">准备拷贝的数据长度</param>
/// <exception cref="IndexOutOfRangeException"></exception>
public void SetBytes( byte[] data, int sourceIndex, int destIndex, int length )
{
if (destIndex < capacity && destIndex >= 0 && data != null)
{
if (length > data.Length) length = data.Length;
hybirdLock.Enter( );
Array.Copy( data, sourceIndex, buffer, destIndex, length );
hybirdLock.Leave( );
}
}
/// <summary>
/// 获取内存指定长度的数据信息
/// </summary>
/// <param name="index">起始位置</param>
/// <param name="length">数组长度</param>
/// <returns>返回实际的数据信息</returns>
public byte[] GetBytes(int index, int length )
{
byte[] result = new byte[length];
if (length > 0)
{
hybirdLock.Enter( );
if (index >= 0 && (index + length) <= buffer.Length)
{
Array.Copy( buffer, index, result, 0, length );
}
hybirdLock.Leave( );
}
return result;
}
/// <summary>
/// 获取内存所有的数据信息
/// </summary>
/// <returns>实际的数据信息</returns>
public byte[] GetBytes( )
{
return GetBytes( 0, capacity );
}
#endregion
#region BCL Set Support
/// <summary>
/// 设置byte类型的数据到缓存区
/// </summary>
/// <param name="value">byte数值</param>
/// <param name="index">索引位置</param>
public void SetValue(byte value, int index )
{
SetBytes( new byte[] { value }, index );
}
/// <summary>
/// 设置short类型的数据到缓存区
/// </summary>
/// <param name="values">short数组</param>
/// <param name="index">索引位置</param>
public void SetValue( short[] values, int index )
{
SetBytes( byteTransform.TransByte( values ), index );
}
/// <summary>
/// 设置short类型的数据到缓存区
/// </summary>
/// <param name="value">short数值</param>
/// <param name="index">索引位置</param>
public void SetValue( short value, int index )
{
SetValue( new short[] { value }, index );
}
/// <summary>
/// 设置ushort类型的数据到缓存区
/// </summary>
/// <param name="values">ushort数组</param>
/// <param name="index">索引位置</param>
public void SetValue( ushort[] values, int index )
{
SetBytes( byteTransform.TransByte( values ), index );
}
/// <summary>
/// 设置ushort类型的数据到缓存区
/// </summary>
/// <param name="value">ushort数值</param>
/// <param name="index">索引位置</param>
public void SetValue( ushort value, int index )
{
SetValue( new ushort[] { value }, index );
}
/// <summary>
/// 设置int类型的数据到缓存区
/// </summary>
/// <param name="values">int数组</param>
/// <param name="index">索引位置</param>
public void SetValue( int[] values, int index )
{
SetBytes( byteTransform.TransByte( values ), index );
}
/// <summary>
/// 设置int类型的数据到缓存区
/// </summary>
/// <param name="value">int数值</param>
/// <param name="index">索引位置</param>
public void SetValue( int value, int index )
{
SetValue( new int[] { value }, index );
}
/// <summary>
/// 设置uint类型的数据到缓存区
/// </summary>
/// <param name="values">uint数组</param>
/// <param name="index">索引位置</param>
public void SetValue(uint[] values, int index )
{
SetBytes( byteTransform.TransByte( values ), index );
}
/// <summary>
/// 设置uint类型的数据到缓存区
/// </summary>
/// <param name="value">uint数值</param>
/// <param name="index">索引位置</param>
public void SetValue( uint value, int index )
{
SetValue( new uint[] { value }, index );
}
/// <summary>
/// 设置float类型的数据到缓存区
/// </summary>
/// <param name="values">float数组</param>
/// <param name="index">索引位置</param>
public void SetValue( float[] values, int index )
{
SetBytes( byteTransform.TransByte( values ), index );
}
/// <summary>
/// 设置float类型的数据到缓存区
/// </summary>
/// <param name="value">float数值</param>
/// <param name="index">索引位置</param>
public void SetValue( float value, int index )
{
SetValue( new float[] { value }, index );
}
/// <summary>
/// 设置long类型的数据到缓存区
/// </summary>
/// <param name="values">long数组</param>
/// <param name="index">索引位置</param>
public void SetValue( long[] values, int index )
{
SetBytes( byteTransform.TransByte( values ), index );
}
/// <summary>
/// 设置long类型的数据到缓存区
/// </summary>
/// <param name="value">long数值</param>
/// <param name="index">索引位置</param>
public void SetValue( long value, int index )
{
SetValue( new long[] { value }, index );
}
/// <summary>
/// 设置ulong类型的数据到缓存区
/// </summary>
/// <param name="values">ulong数组</param>
/// <param name="index">索引位置</param>
public void SetValue( ulong[] values, int index )
{
SetBytes( byteTransform.TransByte( values ), index );
}
/// <summary>
/// 设置ulong类型的数据到缓存区
/// </summary>
/// <param name="value">ulong数值</param>
/// <param name="index">索引位置</param>
public void SetValue( ulong value, int index )
{
SetValue( new ulong[] { value }, index );
}
/// <summary>
/// 设置double类型的数据到缓存区
/// </summary>
/// <param name="values">double数组</param>
/// <param name="index">索引位置</param>
public void SetValue( double[] values, int index )
{
SetBytes( byteTransform.TransByte( values ), index );
}
/// <summary>
/// 设置double类型的数据到缓存区
/// </summary>
/// <param name="value">double数值</param>
/// <param name="index">索引位置</param>
public void SetValue( double value, int index )
{
SetValue( new double[] { value }, index );
}
#endregion
#region BCL Get Support
/// <summary>
/// 获取byte类型的数据
/// </summary>
/// <param name="index">索引位置</param>
/// <returns>byte数值</returns>
public byte GetByte( int index )
{
return GetBytes( index, 1 )[0];
}
/// <summary>
/// 获取short类型的数组到缓存区
/// </summary>
/// <param name="index">索引位置</param>
/// <param name="length">数组长度</param>
/// <returns>short数组</returns>
public short[] GetInt16( int index, int length )
{
byte[] tmp = GetBytes( index, length * 2 );
return byteTransform.TransInt16( tmp, 0, length );
}
/// <summary>
/// 获取short类型的数据到缓存区
/// </summary>
/// <param name="index">索引位置</param>
/// <returns>short数据</returns>
public short GetInt16( int index )
{
return GetInt16( index, 1 )[0];
}
/// <summary>
/// 获取ushort类型的数组到缓存区
/// </summary>
/// <param name="index">索引位置</param>
/// <param name="length">数组长度</param>
/// <returns>ushort数组</returns>
public ushort[] GetUInt16( int index, int length )
{
byte[] tmp = GetBytes( index, length * 2 );
return byteTransform.TransUInt16( tmp, 0, length );
}
/// <summary>
/// 获取ushort类型的数据到缓存区
/// </summary>
/// <param name="index">索引位置</param>
/// <returns>ushort数据</returns>
public ushort GetUInt16( int index )
{
return GetUInt16( index, 1 )[0];
}
/// <summary>
/// 获取int类型的数组到缓存区
/// </summary>
/// <param name="index">索引位置</param>
/// <param name="length">数组长度</param>
/// <returns>int数组</returns>
public int[] GetInt32( int index, int length )
{
byte[] tmp = GetBytes( index, length * 4 );
return byteTransform.TransInt32( tmp, 0, length );
}
/// <summary>
/// 获取int类型的数据到缓存区
/// </summary>
/// <param name="index">索引位置</param>
/// <returns>int数据</returns>
public int GetInt32( int index )
{
return GetInt32( index, 1 )[0];
}
/// <summary>
/// 获取uint类型的数组到缓存区
/// </summary>
/// <param name="index">索引位置</param>
/// <param name="length">数组长度</param>
/// <returns>uint数组</returns>
public uint[] GetUInt32( int index, int length )
{
byte[] tmp = GetBytes( index, length * 4 );
return byteTransform.TransUInt32( tmp, 0, length );
}
/// <summary>
/// 获取uint类型的数据到缓存区
/// </summary>
/// <param name="index">索引位置</param>
/// <returns>uint数据</returns>
public uint GetUInt32( int index )
{
return GetUInt32( index, 1 )[0];
}
/// <summary>
/// 获取float类型的数组到缓存区
/// </summary>
/// <param name="index">索引位置</param>
/// <param name="length">数组长度</param>
/// <returns>float数组</returns>
public float[] GetSingle( int index, int length )
{
byte[] tmp = GetBytes( index, length * 4 );
return byteTransform.TransSingle( tmp, 0, length );
}
/// <summary>
/// 获取float类型的数据到缓存区
/// </summary>
/// <param name="index">索引位置</param>
/// <returns>float数据</returns>
public float GetSingle( int index )
{
return GetSingle( index, 1 )[0];
}
/// <summary>
/// 获取long类型的数组到缓存区
/// </summary>
/// <param name="index">索引位置</param>
/// <param name="length">数组长度</param>
/// <returns>long数组</returns>
public long[] GetInt64( int index, int length )
{
byte[] tmp = GetBytes( index, length * 8 );
return byteTransform.TransInt64( tmp, 0, length );
}
/// <summary>
/// 获取long类型的数据到缓存区
/// </summary>
/// <param name="index">索引位置</param>
/// <returns>long数据</returns>
public long GetInt64( int index )
{
return GetInt64( index, 1 )[0];
}
/// <summary>
/// 获取ulong类型的数组到缓存区
/// </summary>
/// <param name="index">索引位置</param>
/// <param name="length">数组长度</param>
/// <returns>ulong数组</returns>
public ulong[] GetUInt64( int index, int length )
{
byte[] tmp = GetBytes( index, length * 8 );
return byteTransform.TransUInt64( tmp, 0, length );
}
/// <summary>
/// 获取ulong类型的数据到缓存区
/// </summary>
/// <param name="index">索引位置</param>
/// <returns>ulong数据</returns>
public ulong GetUInt64( int index )
{
return GetUInt64( index, 1 )[0];
}
/// <summary>
/// 获取double类型的数组到缓存区
/// </summary>
/// <param name="index">索引位置</param>
/// <param name="length">数组长度</param>
/// <returns>ulong数组</returns>
public double[] GetDouble( int index, int length )
{
byte[] tmp = GetBytes( index, length * 8 );
return byteTransform.TransDouble( tmp, 0, length );
}
/// <summary>
/// 获取double类型的数据到缓存区
/// </summary>
/// <param name="index">索引位置</param>
/// <returns>double数据</returns>
public double GetDouble( int index )
{
return GetDouble( index, 1 )[0];
}
#endregion
#region Customer Support
/// <summary>
/// 读取自定义类型的数据,需要规定解析规则
/// </summary>
/// <typeparam name="T">类型名称</typeparam>
/// <param name="index">起始索引</param>
/// <returns>自定义的数据类型</returns>
public T GetCustomer<T>( int index ) where T : IDataTransfer, new()
{
T Content = new T( );
byte[] read = GetBytes( index, Content.ReadCount );
Content.ParseSource( read );
return Content;
}
/// <summary>
/// 写入自定义类型的数据到缓存中去,需要规定生成字节的方法
/// </summary>
/// <typeparam name="T">自定义类型</typeparam>
/// <param name="data">实例对象</param>
/// <param name="index">起始地址</param>
public void SetCustomer<T>( T data, int index ) where T : IDataTransfer, new()
{
SetBytes( data.ToSource( ), index );
}
#endregion
#region Public Properties
/// <summary>
/// 获取或设置当前的数据缓存类的解析规则
/// </summary>
public IByteTransform ByteTransform
{
get => byteTransform;
set => byteTransform = value;
}
#endregion
#region Private Member
private int capacity = 10; // 缓存的容量
private byte[] buffer; // 缓存的数据
private SimpleHybirdLock hybirdLock; // 高效的混合锁
private IByteTransform byteTransform; // 数据转换类
#endregion
#region IDisposable Support
private bool disposedValue = false; // 要检测冗余调用
/// <summary>
/// 释放当前的对象
/// </summary>
/// <param name="disposing"></param>
protected virtual void Dispose( bool disposing )
{
if (!disposedValue)
{
if (disposing)
{
// TODO: 释放托管状态(托管对象)。
hybirdLock?.Dispose( );
buffer = null;
}
// TODO: 释放未托管的资源(未托管的对象)并在以下内容中替代终结器。
// TODO: 将大型字段设置为 null。
disposedValue = true;
}
}
// TODO: 仅当以上 Dispose(bool disposing) 拥有用于释放未托管资源的代码时才替代终结器。
// ~SoftBuffer()
// {
// // 请勿更改此代码。将清理代码放入以上 Dispose(bool disposing) 中。
// Dispose(false);
// }
// 添加此代码以正确实现可处置模式。
/// <summary>
/// 释放当前的对象
/// </summary>
public void Dispose( )
{
// 请勿更改此代码。将清理代码放入以上 Dispose(bool disposing) 中。
Dispose( true );
// TODO: 如果在以上内容中替代了终结器,则取消注释以下行。
// GC.SuppressFinalize(this);
}
#endregion
}
}