DZone Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world

Snippets has posted 5883 posts at DZone. View Full User Profile

C# (csharp) Bitfields - PackedByte, PackedUShort

04.26.2007
| 909 views |
  • submit to reddit
        In c++ it is possible to have fields smaller than one byte with bitfields:
		struct Tile
		{
			char Type:4;
			bool River:1;
			bool Fortress:1;
			char Road:2;
		};

Below is a way to have bitfields in C#. The speed is quite acceptable, and in this example PackedByte allowed to fit four byte values in one byte.

How to use:
    public struct Tile
    {
        PackedByte data1;
        /// <summary>
        /// 4 bits (0-15)
        /// </summary>
        public byte Type
        {
            get { return (byte)data1.Get(0,4); }
            set { data1.Set(0,4,(byte)value); }
        }
        /// <summary>
        /// 1 bit
        /// </summary>
        public bool River
        {
            get { return data1.Get(4,1)!=0; }
            set { data1.Set(4,1,value?(byte)1:(byte)0); }
        }
        /// <summary>
        /// 1 bit
        /// </summary>
        public bool Fortress
        {
            get { return data1.Get(5,1)!=0; }
            set { data1.Set(5,1,value?(byte)1:(byte)0); }
        }
        /// <summary>
        /// 2 bits (0-3)
        /// </summary>
        public RoadState Road
        {
            get { return (RoadState)data1.Get(6,2); }
            set { data1.Set(6,2,(byte)value); }
        }
    }

    public struct PackedByte
    {
        public PackedByte(byte data)
        {
            this.data=data;
        }
        static byte[] masks=
            {
                0,
                2-1,//1
                4-1,//2
                8-1,//3
                16-1,//4
                32-1,//5
                64-1,//6
                128-1,//7
                256-1,//8
            };
        public byte Get(int start,int count)
        {
            byte mask=masks[count];
            return (byte)((data&(mask<<start))>>start);
        }
        public void Set(int start,int count,byte data)
        {
            byte mask=masks[count];
            if (data>mask)
            {
                throw new ArgumentOutOfRangeException();
            }
            this.data=(byte)(this.data&(~(mask<<start)));
            this.data=(byte)(this.data|((data<<start)));
        }
        byte data;
        public byte Data
        {
            get { return data; }
            set { data=value; }
        }
    }
    public struct PackedUShort
    {
        public PackedUShort(ushort data)
        {
            this.data=data;
        }
        static ushort[] masks=
            {
                0,
                2-1,//1
                4-1,//2
                8-1,//3
                16-1,//4
                32-1,//5
                64-1,//6
                128-1,//7
                256-1,//8
                512-1,//9
                1024-1,//10
                2048-1,//11
                4096-1,//12
                8192-1,//13
                16384-1,//14
                32768-1,//15
                65536-1,//16
            };
        public ushort Get(int start,int count)
        {
            ushort mask=masks[count];
            return (ushort)((data&(mask<<start))>>start);
        }
        public void Set(int start,int count,ushort data)
        {
            ushort mask=masks[count];
            if (data>mask)
            {
                throw new ArgumentOutOfRangeException();
            }
            this.data=(ushort)(this.data&(~(mask<<start)));
            this.data=(ushort)(this.data|((data<<start)));
        }
        ushort data;
        public ushort Data
        {
            get { return data; }
            set { data=value; }
        }
    }