Introduction
We could easily make a useful and various bit-field by combining 'union
' and 'struct
' in C++. But, C# does not have union
but has FieldOffset
, BitVector32
and BitArray
. I tried to make 64Bit-field with FieldOffset
, BitVector32
and BitArray
. BitArray
cannot be used with FieldOffset
, so I passed FieldOffset
over. However, I did manage to make 64Bit-field with FieldOffset
and BitVector32
, Using the index of BitVector32
was still inconvenient. So, I have made it conveniently with 'this' and some bit-wise operator.
Background
I made a 64Bit-Field a long long time ago by referring to books and searching the web. I don't remember exactly but, I found BitVector32
source code suddenly. And then I could make BitVector64
. I'd like to take this opportunity to thank programmers that contribute too.
Using the Code
I don't like to talk a lot so I hope to talk about the core instead. For more details, please refer to the comment of source code. The 'struct
' for 64Bit-Field is like this:
[StructLayout(LayoutKind.Explicit, Size=8, Pack=1, CharSet=CharSet.Ansi)]
public struct Any64
{
#region Int64
[FieldOffset(0)] public Int64 INT64;
#endregion
#region UInt64
[FieldOffset(0)] public UInt64 UINT64;
#endregion
#region double
[FieldOffset(0)] public double DOUBLE;
#endregion
#region float
[FieldOffset(0)] public float FLOAT_0;
[FieldOffset(4)] public float FLOAT_1;
#endregion
#region Uint32
[FieldOffset(0)]
public uint UINT32_0;
[FieldOffset(4)] public uint UINT32_1;
#endregion
#region UInt16
[FieldOffset(0)]
public ushort UINT16_0;
[FieldOffset(2)] public ushort UINT16_1;
[FieldOffset(4)]
public ushort UINT16_2;
[FieldOffset(6)]
public ushort UINT16_3;
#endregion
#region UInt8
[FieldOffset(0)]
public byte UINT8_0;
[FieldOffset(1)] public byte UINT8_1;
[FieldOffset(2)]
public byte UINT8_2;
[FieldOffset(3)]
public byte UINT8_3;
[FieldOffset(4)]
public byte UINT8_4;
[FieldOffset(5)]
public byte UINT8_5;
[FieldOffset(6)]
public byte UINT8_6;
[FieldOffset(7)]
public byte UINT8_7;
#endregion
#region int32
[FieldOffset(0)]
public int INT32_0;
[FieldOffset(4)] public int INT32_1;
#endregion
#region Int16
[FieldOffset(0)]
public short INT16_0;
[FieldOffset(2)] public short INT16_1;
[FieldOffset(4)]
public short INT16_2;
[FieldOffset(6)]
public short INT16_3;
#endregion
#region Int8
[FieldOffset(0)]
public sbyte INT8_0;
[FieldOffset(1)] public sbyte INT8_1;
[FieldOffset(2)]
public sbyte INT8_2;
[FieldOffset(3)]
public sbyte INT8_3;
[FieldOffset(4)]
public sbyte INT8_4;
[FieldOffset(5)]
public sbyte INT8_5;
[FieldOffset(6)]
public sbyte INT8_6;
[FieldOffset(7)]
public sbyte INT8_7;
#endregion
#region Bit [FieldOffset(0)]
private BitVector32 LowBits;
[FieldOffset(4)] private BitVector32 HighBits;
[FieldOffset(0)]
private BitVector64 Bits;
#endregion
public bool this[int index]
{
get{ return Bits[(long)(1 << index)];}
set{ Bits[(long)(1 << index)] = value;}
}
}
I made 'BitVector64
' just with remodeling 'BitVector32
' source code. Please allow me to leave out the explanation. Once again, I'd like to take this opportunity to thank programmers that contribute too. The 'struct
' of 'BitVector64
' is like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.Specialized;
namespace INS.BaseLib
{
public struct BitVector64
{
long data;
#region Section
public struct Section
{
private short mask;
private short offset;
internal Section(short mask, short offset)
{
this.mask = mask;
this.offset = offset;
}
public short Mask
{
get { return mask; }
}
public short Offset
{
get { return offset; }
}
#if NET_2_0
public static bool operator == (Section v1, Section v2)
{
return v1.mask == v2.mask &&
v1.offset == v2.offset;
}
public static bool operator != (Section v1, Section v2)
{
return v1.mask != v2.mask &&
v1.offset != v2.offset;
}
public bool Equals (Section obj)
{
return this.mask == obj.mask &&
this.offset == obj.offset;
}
#endif
public override bool Equals(object o)
{
if (!(o is Section))
return false;
Section section = (Section)o;
return this.mask == section.mask &&
this.offset == section.offset;
}
public override int GetHashCode()
{
return (((Int16)mask).GetHashCode() << 16) +
((Int16)offset).GetHashCode();
}
public override string ToString()
{
return "Section{0x" + Convert.ToString(mask, 16) +
", 0x" + Convert.ToString(offset, 16) + "}";
}
public static string ToString(Section value)
{
StringBuilder b = new StringBuilder();
b.Append("Section{0x");
b.Append(Convert.ToString(value.Mask, 16));
b.Append(", 0x");
b.Append(Convert.ToString(value.Offset, 16));
b.Append("}");
return b.ToString();
}
}
#endregion
#region Constructors
public BitVector64(BitVector64 source)
{
this.data = source.data;
}
public BitVector64(BitVector32 source)
{
this.data = source.Data;
}
public BitVector64(long source)
{
this.data = source;
}
public BitVector64(int init)
{
this.data = init;
}
#endregion
#region Properties
public long Data
{
get { return this.data; }
}
public long this[BitVector64.Section section]
{
get
{
return ((data >> section.Offset) & section.Mask);
}
set
{
if (value < 0)
throw new ArgumentException("Section can't hold negative values");
if (value > section.Mask)
throw new ArgumentException("Value too large to fit in section");
this.data &= ~(section.Mask << section.Offset);
this.data |= (value << section.Offset);
}
}
public bool this[long mask]
{
get
{
#if NET_2_0
return (this.data & mask) == mask;
#else
long tmp = this.data;
return (tmp & (long)mask) == (long)mask;
#endif
}
set
{
if (value)
this.data |= mask;
else
this.data &= ~mask;
}
}
#endregion
public static long CreateMask()
{
return CreateMask(0); }
public static long CreateMask(long prev)
{
if (prev == 0)
return 1;
if (prev == Int64.MinValue)
throw new InvalidOperationException("all bits set");
return prev << 1;
}
public static Section CreateSection(int maxValue)
{
return CreateSection(maxValue, new Section(0, 0));
}
public static Section CreateSection(int maxValue, BitVector64.Section previous)
{
if (maxValue < 1)
throw new ArgumentException("maxValue");
int bit = HighestSetBit(maxValue) + 1;
int mask = (1 << bit) - 1;
int offset = previous.Offset + NumberOfSetBits(previous.Mask);
if (offset > 64)
{
throw new ArgumentException("Sections cannot exceed 64 bits in total");
}
return new Section((short)mask, (short)offset);
}
public override bool Equals(object o)
{
if (!(o is BitVector64))
return false;
return data == ((BitVector64)o).data;
}
public override int GetHashCode()
{
return data.GetHashCode();
}
public override string ToString()
{
return ToString(this);
}
public static string ToString(BitVector64 value)
{
StringBuilder sb = new StringBuilder(0x2d);
sb.Append("BitVector64{");
ulong data = (ulong)value.Data;
for (int i = 0; i < 0x40; i++)
{
sb.Append(((data & 0x8000000000000000) == 0) ? '0' : '1');
data = data << 1;
}
sb.Append("}");
return sb.ToString();
}
private static int NumberOfSetBits(int i)
{
int count = 0;
for (int bit = 0; bit < 64; bit++)
{
int mask = 1 << bit;
if ((i & mask) != 0)
count++;
}
return count;
}
private static int HighestSetBit(int i)
{
for (int bit = 63; bit >= 0; bit--)
{
int mask = 1 << bit;
if ((mask & i) != 0)
{
return bit;
}
}
return -1;
}
}
}
How To Use
You can find that the value of any other type also got surprisingly changed if a value is set to 'INT64
', UINT8_5
and so on.
INS.BaseLib.Any64 bitField64 = new INS.BaseLib.Any64();
bitField64.INT64 = 255;
bitField64.UINT8_5 = 17;
bitField64[5] = true;
bool bValues = bitField64[63];
Points of Interest
You can get the value of wanted type from the value of any type. Even double
or float
. So, you don't need the complex calculation to get double
value from integer values.
If you have any questions and suggestions about this tip, please don't hesitate to let me know.