⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 memoryarray.cs

📁 对gif
💻 CS
📖 第 1 页 / 共 2 页
字号:
using System;
using System.Runtime.InteropServices;
using System.Collections;
using System.Collections.Generic;

namespace FreeImageAPI
{
	/// <summary>
	/// Represents unmanaged memory, containing an array of a given structure.
	/// </summary>
	/// <typeparam name="T">Structuretype represented by the instance.</typeparam>
	/// <remarks>
	/// <see cref="System.Boolean"/> and <see cref="System.Char"/> can not be marshalled.
	/// <para/>
	/// Use <see cref="System.Int32"/> instead of <see cref="System.Boolean"/> and
	/// <see cref="System.Byte"/> instead of <see cref="System.Char"/>.
	/// </remarks>
	public unsafe class MemoryArray<T> : ICloneable, ICollection, IEnumerable<T>, IEquatable<MemoryArray<T>> where T : struct
	{
		/// <summary>
		/// Baseaddress of the wrapped memory.
		/// </summary>
		protected readonly byte* baseAddress;

		/// <summary>
		/// Number of elements being wrapped.
		/// </summary>
		protected readonly int length;

		/// <summary>
		/// Size, in bytes, of each element.
		/// </summary>
		protected readonly int size;

		/// <summary>
		/// Array of <b>T</b> containing a single element.
		/// The array is used as a workaround, because there are no pointer for generic types.
		/// </summary>
		protected readonly T[] buffer;

		/// <summary>
		/// Pointer to the element of <b>buffer</b>.
		/// </summary>
		protected readonly byte* ptr;

		/// <summary>
		/// Handle for pinning <b>buffer</b>.
		/// </summary>
		protected readonly GCHandle handle;

		/// <summary>
		/// Indicates whether the wrapped memory is handled like a bitfield.
		/// </summary>
		protected readonly bool isOneBit;

		/// <summary>
		/// Indicates whther the wrapped memory is handles like 4-bit blocks.
		/// </summary>
		protected readonly bool isFourBit;

		/// <summary>
		/// An object that can be used to synchronize access to the <see cref="MemoryArray&lt;T&gt;"/>.
		/// </summary>
		protected object syncRoot = null;

		/// <summary>
		/// Initializes a new instance.
		/// </summary>
		protected MemoryArray()
		{
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="MemoryArray&lt;T&gt;"/> class. 
		/// </summary>
		/// <param name="baseAddress">Address of the memory block.</param>
		/// <param name="length">Length of the array.</param>
		/// <exception cref="ArgumentNullException">
		/// <paramref name="baseAddress"/> is null.</exception>
		/// <exception cref="ArgumentOutOfRangeException">
		/// <paramref name="length"/> is less or equal zero.</exception>
		/// <exception cref="NotSupportedException">
		/// The type is not supported.</exception>
		public MemoryArray(IntPtr baseAddress, int length)
			: this(baseAddress.ToPointer(), length)
		{
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="MemoryArray&lt;T&gt;"/> class. 
		/// </summary>
		/// <param name="baseAddress">Address of the memory block.</param>
		/// <param name="length">Length of the array.</param>
		/// <exception cref="ArgumentNullException">
		/// <paramref name="baseAddress"/> is null.</exception>
		/// <exception cref="ArgumentOutOfRangeException">
		/// <paramref name="length"/> is less or equal zero.</exception>
		/// <exception cref="NotSupportedException">
		/// The type is not supported.</exception>
		public MemoryArray(void* baseAddress, int length)
		{
			if (typeof(T) == typeof(FI1BIT))
			{
				isOneBit = true;
			}
			else if (typeof(T) == typeof(FI4BIT))
			{
				isFourBit = true;
			}
			else
			{
				T[] dummy = new T[2];
				long marshalledSize = Marshal.SizeOf(typeof(T));
				long structureSize =
					Marshal.UnsafeAddrOfPinnedArrayElement(dummy, 1).ToInt64() -
					Marshal.UnsafeAddrOfPinnedArrayElement(dummy, 0).ToInt64();
				if (marshalledSize != structureSize)
				{
					throw new NotSupportedException(
						"The desired type can not be handled, " +
						"because it's managed and unmanaged size in bytes are different.");
				}
			}

			if (baseAddress == null)
			{
				throw new ArgumentNullException("baseAddress");
			}
			if (length < 1)
			{
				throw new ArgumentOutOfRangeException("length");
			}

			this.baseAddress = (byte*)baseAddress;
			this.length = (int)length;

			if (!isOneBit && !isFourBit)
			{
				this.size = Marshal.SizeOf(typeof(T));
				// Create an array containing a single element.
				// Due to the fact, that it's not possible to create pointers
				// of generic types, an array is used to obtain the memory
				// address of an element of T.
				this.buffer = new T[1];
				// The array is pinned immediately to prevent the GC from
				// moving it to a different position in memory.
				this.handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
				// The array and its content have beed pinned, so that its address
				// can be safely requested and stored for the whole lifetime
				// of the instace.
				this.ptr = (byte*)Marshal.UnsafeAddrOfPinnedArrayElement(this.buffer, 0);
			}
		}

		/// <summary>
		/// Frees the allocated <see cref="System.Runtime.InteropServices.GCHandle"/>.
		/// </summary>
		~MemoryArray()
		{
			if (handle.IsAllocated)
			{
				handle.Free();
			}
		}

		/// <summary>
		/// Tests whether two specified <see cref="MemoryArray&lt;T&gt;"/> structures are equivalent.
		/// </summary>
		/// <param name="left">The <see cref="MemoryArray&lt;T&gt;"/> that is to the left of the equality operator.</param>
		/// <param name="right">The <see cref="MemoryArray&lt;T&gt;"/> that is to the right of the equality operator.</param>
		/// <returns>
		/// <b>true</b> if the two <see cref="MemoryArray&lt;T&gt;"/> structures are equal; otherwise, <b>false</b>.
		/// </returns>
		public static bool operator ==(MemoryArray<T> left, MemoryArray<T> right)
		{
			if (object.ReferenceEquals(left, right))
			{
				return true;
			}
			if (object.ReferenceEquals(right, null) ||
				object.ReferenceEquals(left, null) ||
				(left.length != right.length))
			{
				return false;
			}
			if (left.baseAddress == right.baseAddress)
			{
				return true;
			}
			return FreeImage.CompareMemory(left.baseAddress, right.baseAddress, (uint)left.length);
		}

		/// <summary>
		/// Tests whether two specified <see cref="MemoryArray&lt;T&gt;"/> structures are different.
		/// </summary>
		/// <param name="left">The <see cref="MemoryArray&lt;T&gt;"/> that is to the left of the inequality operator.</param>
		/// <param name="right">The <see cref="MemoryArray&lt;T&gt;"/> that is to the right of the inequality operator.</param>
		/// <returns>
		/// <b>true</b> if the two <see cref="MemoryArray&lt;T&gt;"/> structures are different; otherwise, <b>false</b>.
		/// </returns>
		public static bool operator !=(MemoryArray<T> left, MemoryArray<T> right)
		{
			return (!(left == right));
		}

		/// <summary>
		/// Gets the value at the specified position.
		/// </summary>
		/// <param name="index">A 32-bit integer that represents the position
		/// of the array element to get.</param>
		/// <returns>The value at the specified position.</returns>
		/// <exception cref="ArgumentOutOfRangeException">
		/// <paramref name="index"/> is outside the range of valid indexes
		/// for the unmanaged array.</exception>
		public T GetValue(int index)
		{
			if ((index >= this.length) || (index < 0))
			{
				throw new ArgumentOutOfRangeException("index");
			}

			return GetValueInternal(index);
		}

		private T GetValueInternal(int index)
		{
			if (isOneBit)
			{
				return (T)(object)(FI1BIT)(((baseAddress[index / 8] & ((1 << (7 - (index % 8))))) == 0) ? 0 : 1);
			}
			else if (isFourBit)
			{
				return (T)(object)(FI4BIT)(((index % 2) == 0) ? (baseAddress[index / 2] >> 4) : (baseAddress[index / 2] & 0x0F));
			}
			else
			{
				CopyMemory(ptr, baseAddress + (index * size), size);
				return buffer[0];
			}
		}

		/// <summary>
		/// Sets a value to the element at the specified position.
		/// </summary>
		/// <param name="value">The new value for the specified element.</param>
		/// <param name="index">A 32-bit integer that represents the
		/// position of the array element to set.</param>
		/// <exception cref="ArgumentOutOfRangeException">
		/// <paramref name="index"/> is outside the range of valid indexes
		/// for the unmanaged array.</exception>
		public void SetValue(T value, int index)
		{
			if ((index >= this.length) || (index < 0))
			{
				throw new ArgumentOutOfRangeException("index");
			}
			SetValueInternal(value, index);
		}

		private void SetValueInternal(T value, int index)
		{
			if (isOneBit)
			{
				if ((FI1BIT)(object)value != 0)
				{
					baseAddress[index / 8] |= (byte)(1 << (7 - (index % 8)));
				}
				else
				{
					baseAddress[index / 8] &= (byte)(~(1 << (7 - (index % 8))));
				}
			}
			else if (isFourBit)
			{
				if ((index % 2) == 0)
				{
					baseAddress[index / 2] = (byte)((baseAddress[index / 2] & 0x0F) | ((FI4BIT)(object)value << 4));
				}
				else
				{
					baseAddress[index / 2] = (byte)((baseAddress[index / 2] & 0xF0) | ((FI4BIT)(object)value & 0x0F));
				}
			}
			else
			{
				buffer[0] = value;
				CopyMemory(baseAddress + (index * size), ptr, size);
			}
		}

		/// <summary>
		/// Gets the values at the specified position and length.
		/// </summary>
		/// <param name="index">A 32-bit integer that represents the position
		/// of the array elements to get.</param>
		/// <param name="length"> A 32-bit integer that represents the length
		/// of the array elements to get.</param>
		/// <returns>The values at the specified position and length.</returns>
		/// <exception cref="ArgumentOutOfRangeException">
		/// <paramref name="index"/> is outside the range of valid indexes
		/// for the unmanaged array or <paramref name="length"/> is greater than the number of elements
		/// from <paramref name="index"/> to the end of the unmanaged array.</exception>
		public T[] GetValues(int index, int length)
		{
			if ((index >= this.length) || (index < 0))
			{
				throw new ArgumentOutOfRangeException("index");
			}
			if (((index + length) > this.length) || (length < 1))
			{
				throw new ArgumentOutOfRangeException("length");
			}

			T[] data = new T[length];
			if (isOneBit || isFourBit)
			{
				for (int i = 0; i < length; i++)
				{
					data[i] = GetValueInternal(i);
				}
			}
			else
			{
				GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned);
				byte* dst = (byte*)Marshal.UnsafeAddrOfPinnedArrayElement(data, 0);
				CopyMemory(dst, baseAddress + (size * index), size * length);
				handle.Free();
			}
			return data;
		}

		/// <summary>
		/// Sets the values at the specified position.
		/// </summary>
		/// <param name="values">An array containing the new values for the specified elements.</param>
		/// <param name="index">A 32-bit integer that represents the position
		/// of the array elements to set.</param>
		/// <exception cref="ArgumentNullException">
		/// <paramref name="values"/> is a null reference (Nothing in Visual Basic).</exception>
		/// <exception cref="ArgumentOutOfRangeException">
		/// <paramref name="index"/> is outside the range of valid indexes
		/// for the unmanaged array or <paramref name="values.Length"/> is greater than the number of elements
		/// from <paramref name="index"/> to the end of the array.</exception>
		public void SetValues(T[] values, int index)
		{
			if (values == null)
			{
				throw new ArgumentNullException("values");
			}
			if ((index >= this.length) || (index < 0))
			{
				throw new ArgumentOutOfRangeException("index");
			}
			if ((index + values.Length) > this.length)
			{
				throw new ArgumentOutOfRangeException("values.Length");
			}

			if (isOneBit || isFourBit)
			{
				for (int i = 0; i != values.Length; )
				{
					SetValueInternal(values[i++], index++);
				}
			}
			else
			{
				GCHandle handle = GCHandle.Alloc(values, GCHandleType.Pinned);
				byte* src = (byte*)Marshal.UnsafeAddrOfPinnedArrayElement(values, 0);
				CopyMemory(baseAddress + (index * size), src, size * length);
				handle.Free();
			}
		}

		/// <summary>
		/// Copies the entire array to a compatible one-dimensional <see cref="System.Array"/>,
		/// starting at the specified index of the target array.
		/// </summary>
		/// <param name="array">The one-dimensional <see cref="System.Array"/> that is the destination
		/// of the elements copied from <see cref="MemoryArray&lt;T&gt;"/>.
		/// The <see cref="System.Array"/> must have zero-based indexing.</param>
		/// <param name="index">The zero-based index in <paramref name="array"/>
		/// at which copying begins.</param>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -