C# Tips:UInt64MaskHelper

本文是《C# Tips:位运算相关》的Update。对《C# Tips:位运算相关》中所定义的类 UInt64MaskHelper,增加了一个实用函数,然后再给出了一个小例子。

这个类设计的用意是方便二进制数据包的 Encoding / Decoding。


先贴出更新后的 UInt64MaskHelper 类

// -----------------------------------------------------------------------
// <copyright file="UInt64MaskHelper.cs" author="Yaping Xin">
//
//
//  File Name           : UInt64MaskHelper.cs
//  Description         : Helper class to support UInt64 bit mask.
//  Project Title       : UInt64MaskHelper
//  Author(s)           : Yaping Xin
//  Code Review Done    :
//  Modification History: (1) Created at Aug 10, 2012
//                      : (2) Add static function bool[] GetBits(ulong value)
//                      :     at Sep 25, 2012 
// </copyright>
// -----------------------------------------------------------------------
namespace BitsHelper
{
    using System;
    using System.Globalization;

    /// <summary>
    /// Helper class to support UInt64 bit mask.
    /// </summary>
    public static class UInt64MaskHelper
    {
        #region Constant definition
        /// <summary>
        /// Constant definition of max avaiable bytes length.
        /// </summary>
        public const int MaxBytesLength = 8;

        /// <summary>
        /// Constant definition bits count within a byte
        /// </summary>
        public const int ByteBitsCount = 8;
        #endregion Constant definition

        #region Useful Bytes/Bits static readonly array definition
        /// <summary>
        /// Array of UInt64 byte mask values.
        /// </summary>
        private static readonly ulong[] U64ByteMaskValues = new ulong[]
        {
            0x00000000000000FF, 
            0x000000000000FF00, 
            0x0000000000FF0000, 
            0x00000000FF000000, 
            0x000000FF00000000, 
            0x0000FF0000000000, 
            0x00FF000000000000, 
            0xFF00000000000000
        };

        /// <summary>
        /// Array of max values storaged in different amount of bytes within UInt64 scope. 
        /// </summary>
        private static readonly ulong[] U64BytesMaxValues = new ulong[]
        {
            0x00000000000000FF,
            0x000000000000FFFF,
            0x0000000000FFFFFF,
            0x00000000FFFFFFFF,
            0x000000FFFFFFFFFF,
            0x0000FFFFFFFFFFFF,
            0x00FFFFFFFFFFFFFF,
            0xFFFFFFFFFFFFFFFF
        };

        /// <summary>
        /// Array of shift values to specific byte lowest bit position.
        /// </summary>
        private static readonly byte[] BytePositionShiftValues = new byte[]
        {
            0, 8, 16, 24, 32, 40, 48, 56
        };

        /// <summary>
        /// Array of byte bit mask values.
        /// </summary>
        private static readonly byte[] ByteBitMaskValues = new byte[]
        {
            0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80
        };

        /// <summary>
        /// Array of byte bit mask values.
        /// </summary>
        private static readonly byte[] ByteBitOffMaskValues = new byte[]
        {
            0xFE, 0xFD, 0xFB, 0xF7, 0xEF, 0xDF, 0xBF, 0x7F
        };
        #endregion Useful Bytes/Bits static readonly array definition

        #region Enumeration definition
        /// <summary>
        /// Enumeration definition of the error code
        /// </summary>
        public enum ErrorCode : uint
        {
            /// <summary>No error occurs</summary>
            OK = 0,

            /// <summary>Argument is Null</summary>
            ArgumentIsNull = 1,

            /// <summary>Argument is out of range</summary>
            ArgumentOutOfRange = 2,
        }
        #endregion Enumeration definition

        #region Encoding methods (numeric value to bytes/bits)
        /// <summary>
        /// Gets the bytes array to storage the specific UInt64 value.
        /// Notes: the returned array contains MaxBytesLength items.
        /// </summary>
        /// <param name="value">The specific UInt64 value.</param>
        /// <returns>The bytes array which contains MaxBytesLength items.</returns>
        public static byte[] GetBytes(ulong value)
        {
            byte[] result = new byte[MaxBytesLength];

            ulong maskResult = value & U64ByteMaskValues[0];
            result[0] = (byte)maskResult;

            for (int i = 1; i < MaxBytesLength; i++)
            {
                maskResult = value & U64ByteMaskValues[i];
                result[i] = (byte)(maskResult >> BytePositionShiftValues[i]);
            }

            return result;
        }

        /// <summary>
        /// Gets the bits array to storage the specific UInt64 value.
        /// Notes: the returned array contains MaxBytesLength * ByteBitsCount items.
        /// </summary>
        /// <param name="value">The specific UInt64 value.</param>
        /// <returns>The bits array which contains MaxBytesLength * ByteBitsCount items.</returns>
        public static bool[] GetBits(ulong value)
        {
            bool[] bits = new bool[MaxBytesLength * ByteBitsCount];
            byte[] bytes = UInt64MaskHelper.GetBytes(value);

            byte byteValue;
            byte bitValue;
            byte mask;

            int i = 0;

            for (int indexBytes = 0; indexBytes < bytes.Length; indexBytes++)
            {
                for (byte bitPosition = 0; bitPosition < ByteBitsCount; bitPosition++)
                {
                    byteValue = bytes[indexBytes];

                    if (bitPosition == 0)
                    {
                        bitValue = (byte)(byteValue & ByteBitMaskValues[0]);
                    }
                    else
                    {
                        mask = (byte)(byteValue & ByteBitMaskValues[bitPosition]);
                        bitValue = mask >>= bitPosition;
                    }

                    bits[i] = bitValue == 1;
                    i++;
                }
            }

            return bits;
        }

        /// <summary>
        /// Gets the byte at specific position from the UInt64 value.
        /// Notes: this function will not return detailed error code while error occurs.
        /// </summary>
        /// <param name="value">The UInt64 value.</param>
        /// <param name="bytePosition">The byte position.</param>
        /// <param name="result">The byte to get.</param>
        /// <returns>
        ///   <c>true</c> indicates no error occurs during calculating; 
        ///   <c>fasle</c> indicates error occurs.
        /// </returns>
        public static bool GetByte(ulong value, int bytePosition, out byte result)
        {
            ErrorCode errorCode;
            return UInt64MaskHelper.GetByte(value, bytePosition, out result, out errorCode);
        }

        /// <summary>
        /// Gets the byte at specific position from the UInt64 value.
        /// </summary>
        /// <param name="value">The UInt64 value.</param>
        /// <param name="bytePosition">The byte position.</param>
        /// <param name="result">The byte to get.</param>
        /// <param name="errorCode">The error code.
        /// Will be set to ErrorCode.OK if no error occurs.</param>
        /// <returns>
        ///   <c>true</c> indicates no error occurs during calculating; 
        ///   <c>fasle</c> indicates error occurs, and detailed error is wrote in errorCode output parameter.
        /// </returns>
        public static bool GetByte(
            ulong value,
            int bytePosition,
            out byte result,
            out ErrorCode errorCode)
        {
            if (bytePosition < 0 || bytePosition >= MaxBytesLength)
            {
                result = 0;
                errorCode = ErrorCode.ArgumentOutOfRange;
                return false;
            }

            ulong maskResult;

            if (bytePosition == 0)
            {
                maskResult = value & U64ByteMaskValues[0];

                goto EXIT_PASS;
            }

            maskResult = value & U64ByteMaskValues[bytePosition];
            maskResult >>= BytePositionShiftValues[bytePosition];

        EXIT_PASS:
            result = (byte)maskResult;
            errorCode = ErrorCode.OK;
            return true;
        }

        /// <summary>
        /// Gets the bit at specific position from the byte value.
        /// Notes: this function will not return detailed error code while error occurs.
        /// </summary>
        /// <param name="value">The byte value.</param>
        /// <param name="bitPosition">The bit position.</param>
        /// <param name="result">The bit (0 or 1) to get.</param>
        /// <returns>
        ///   <c>true</c> indicates no error occurs during calculating; 
        ///   <c>fasle</c> indicates error occurs.
        /// </returns>
        public static bool GetBit(byte value, int bitPosition, out byte result)
        {
            ErrorCode errorCode;
            return UInt64MaskHelper.GetBit(value, bitPosition, out result, out errorCode);
        }

        /// <summary>
        /// Gets the bit at specific position from the byte value.
        /// </summary>
        /// <param name="value">The byte value.</param>
        /// <param name="bitPosition">The bit position.</param>
        /// <param name="result">The bit (0 or 1) to get.</param>
        /// <param name="errorCode">The error code.
        /// Will be set to ErrorCode.OK if no error occurs.</param>
        /// <returns>
        ///   <c>true</c> indicates no error occurs during calculating; 
        ///   <c>fasle</c> indicates error occurs, and detailed error is wrote in errorCode output parameter.
        /// </returns>
        public static bool GetBit(
            byte value,
            int bitPosition,
            out byte result,
            out ErrorCode errorCode)
        {
            if (bitPosition < 0 || bitPosition >= ByteBitsCount)
            {
                result = 0;
                errorCode = ErrorCode.ArgumentOutOfRange;
                return false;
            }

            if (bitPosition == 0)
            {
                result = (byte)(value & ByteBitMaskValues[0]);
                errorCode = ErrorCode.OK;
                return true;
            }

            byte maskResult = (byte)(value & ByteBitMaskValues[bitPosition]);
            result = maskResult >>= bitPosition;
            errorCode = ErrorCode.OK;
            return true;
        }
        #endregion Encoding methods (numeric value to bytes/bits)

        #region Decoding methods (bytes/bits to numeric value)
        /// <summary>
        /// Gets the UInt64 value from bytes array.
        /// Notes: this function will not return detailed error code while error occurs.
        /// </summary>
        /// <param name="bytes">The bytes array.</param>
        /// <param name="value">The UInt64 value.</param>
        /// <returns>
        ///   <c>true</c> indicates no error occurs during calculating; 
        ///   <c>fasle</c> indicates error occurs.
        /// </returns>
        public static bool GetUInt64(byte[] bytes, out ulong value)
        {
            ErrorCode errorCode;
            return UInt64MaskHelper.GetUInt64(bytes, out value, out errorCode);
        }

        /// <summary>
        /// Gets the UInt64 value from bytes array.
        /// </summary>
        /// <param name="bytes">The bytes array.</param>
        /// <param name="value">The UInt64 value.</param>
        /// <param name="errorCode">The error code.
        /// Will be set to ErrorCode.OK if no error occurs.</param>
        /// <returns>
        ///   <c>true</c> indicates no error occurs during calculating; 
        ///   <c>fasle</c> indicates error occurs, and detailed error is wrote in errorCode output parameter.
        /// </returns>
        public static bool GetUInt64(byte[] bytes, out ulong value, out ErrorCode errorCode)
        {
            if (bytes == null || bytes.Length == 0)
            {
                errorCode = ErrorCode.ArgumentIsNull;
                value = 0;
                return false;
            }

            if (bytes.Length > MaxBytesLength)
            {
                errorCode = ErrorCode.ArgumentOutOfRange;
                value = 0;
                return false;
            }

            ulong result = bytes[0];
            ulong byteValue;

            if (bytes.Length > 1)
            {
                for (int i = 1; i < bytes.Length; i++)
                {
                    byteValue = bytes[i];
                    byteValue <<= BytePositionShiftValues[i];
                    result += byteValue;
                }
            }

            value = result;
            errorCode = ErrorCode.OK;
            return true;
        }

        /// <summary>
        /// Gets the UInt64 value from text.
        /// </summary>
        /// <param name="hexText">The hex or decimal text.</param>
        /// <param name="result">The UInt64 value.</param>
        /// <returns>
        ///   <c>true</c> indicates no error occurs during calculating; 
        ///   <c>fasle</c> indicates error occurs.
        /// </returns>
        public static bool GetUInt64(string hexText, out ulong result)
        {
            if (string.IsNullOrEmpty(hexText))
            {
                goto EXIT_FAIL;
            }

            try
            {
                if (hexText.StartsWith("0x", StringComparison.CurrentCultureIgnoreCase))
                {
                    return ulong.TryParse(
                        hexText.Substring(2).Trim(),
                        NumberStyles.AllowHexSpecifier,
                        null,
                        out result);
                }
                else
                {
                    return ulong.TryParse(hexText.Trim(), out result);
                }
            }
            catch
            {
                goto EXIT_FAIL;
            }

        EXIT_FAIL:
            result = 0;
            return false;
        }
        #endregion Decoding methods (bytes/bits to numeric value)

        #region Set bit value
        /// <summary>
        /// Sets bit value at specific bit position within the raw byte.
        /// Notes: this function will not return detailed error code while error occurs.
        /// </summary>
        /// <param name="rawByte">The raw byte.</param>
        /// <param name="bitPosition">The bit position.</param>
        /// <param name="bitValue">if set to <c>true</c> [bit value].</param>
        /// <returns>
        ///   <c>true</c> indicates no error occurs during calculating; 
        ///   <c>fasle</c> indicates error occurs.
        /// </returns>
        public static bool SetBit(ref byte rawByte, int bitPosition, bool bitValue)
        {
            ErrorCode errorCode;
            return UInt64MaskHelper.SetBit(ref rawByte, bitPosition, bitValue, out errorCode);
        }

        /// <summary>
        /// Sets bit value at specific bit position within the raw byte.
        /// </summary>
        /// <param name="rawByte">The raw byte.</param>
        /// <param name="bitPosition">The bit position.</param>
        /// <param name="bitValue"><c>true</c> indicates set bit value to 1; 
        /// otherwise set bit value to 0.</param>
        /// <param name="errorCode">The error code.
        /// Will be set to ErrorCode.OK if no error occurs.</param>
        /// <returns>
        ///   <c>true</c> indicates no error occurs during calculating; 
        ///   <c>fasle</c> indicates error occurs, and detailed error is wrote in errorCode output parameter.
        /// </returns>
        public static bool SetBit(ref byte rawByte, int bitPosition, bool bitValue, out ErrorCode errorCode)
        {
            if (bitPosition < 0 || bitPosition >= ByteBitsCount)
            {
                errorCode = ErrorCode.ArgumentOutOfRange;
                return false;
            }

            if (bitValue)
            {
                rawByte |= ByteBitMaskValues[bitPosition];
            }
            else
            {
                rawByte &= ByteBitOffMaskValues[bitPosition];
            }

            errorCode = ErrorCode.OK;
            return true;
        }
        #endregion Set bit value
    }
}





应用举例


比如说,我们需要把一个 UInt64 值解析成 byte 数组,那么我们可以用到这个类里面的这个静态方法:

        /// <summary>
        /// Gets the bytes array to storage the specific UInt64 value.
        /// Notes: the returned array contains MaxBytesLength items.
        /// </summary>
        /// <param name="value">The specific UInt64 value.</param>
        /// <returns>The bytes array which contains MaxBytesLength items.</returns>
        public static byte[] GetBytes(ulong value)
        {
            byte[] result = new byte[MaxBytesLength];

            ulong maskResult = value & U64ByteMaskValues[0];
            result[0] = (byte)maskResult;

            for (int i = 1; i < MaxBytesLength; i++)
            {
                maskResult = value & U64ByteMaskValues[i];
                result[i] = (byte)(maskResult >> BytePositionShiftValues[i]);
            }

            return result;
        }

如果需要把一个 UInt64 值解析成 bit 数组,那么我们可以用到这个类里面的这个静态方法(我们用 bool 数组来存放 bit 值):

        /// <summary>
        /// Gets the bits array to storage the specific UInt64 value.
        /// Notes: the returned array contains MaxBytesLength * ByteBitsCount items.
        /// </summary>
        /// <param name="value">The specific UInt64 value.</param>
        /// <returns>The bits array which contains MaxBytesLength * ByteBitsCount items.</returns>
        public static bool[] GetBits(ulong value)
        {
            bool[] bits = new bool[MaxBytesLength * ByteBitsCount];
            byte[] bytes = UInt64MaskHelper.GetBytes(value);

            byte byteValue;
            byte bitValue;
            byte mask;

            int i = 0;

            for (int indexBytes = 0; indexBytes < bytes.Length; indexBytes++)
            {
                for (byte bitPosition = 0; bitPosition < ByteBitsCount; bitPosition++)
                {
                    byteValue = bytes[indexBytes];

                    if (bitPosition == 0)
                    {
                        bitValue = (byte)(byteValue & ByteBitMaskValues[0]);
                    }
                    else
                    {
                        mask = (byte)(byteValue & ByteBitMaskValues[bitPosition]);
                        bitValue = mask >>= bitPosition;
                    }

                    bits[i] = bitValue == 1;
                    i++;
                }
            }

            return bits;
        }

Notes:

  1. 常量 MaxBytesLength 和 ByteBitsCount 的值都是 8。
  2. public static byte[] GetBytes(ulong value) 返回值是一个长度为 8 的 byte 数组;
  3. public static bool[] GetBits(ulong value) 返回值是一个长度为 64 的 bool 数组;


测试一下 bool[] GetBits(ulong value) 函数:


测试程序如下:

        static void Main(string[] args)
        {
            ulong value = 0xFF01FF02FF03FF04;
            bool[] bits = UInt64MaskHelper.GetBits(value);

            if (bits.Length == 64)
            {
                for (int i = 63; i >= 0; i--)
                {
                    bool bitValue = bits[i];
                    if (bitValue)
                    {
                        Console.Write("1");
                    }
                    else
                    {
                        Console.Write("0");
                    }

                    if (i % 4 == 0)
                    {
                        Console.Write(" ");
                    }

                    if (i % 32 == 0)
                    {
                        Console.WriteLine();
                    }
                }

                Console.WriteLine();
            }
        }


运行结果:

验证:我们用Windows 7自带的计算器来作为验证工具。Windows 7自带的计算器的 Programmer 模式可以显示出一个值的二进制形式:

从上面的截图中我们可以看到,我们的程序输出的结果是正确的。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值