c# 指针的操作

/// <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;
            }
        }
    }

 

posted @ 2021-02-18 17:53  lcawen  阅读(185)  评论(0)    收藏  举报