views:

189

answers:

5

What is the best way of defining in C# a structure with, say, 6 bits of data? I can, of course, define 2 fields of int + short, but I wonder if there's a way of holding all the data in 1 filed.

Regards, Yaakov

+2  A: 

You an use the BitArray class for this purpose. It's in System.Collections

http://msdn.microsoft.com/en-us/library/system.collections.bitarray.aspx

TimothyP
BitArray manages a compact array of bit values, which are represented as Booleans, where true indicates that the bit is on (1) and false indicates the bit is off (0) like MSDN says, bool is not 1 bit in C# so I think BitArray is not an answer
ArsenMkrt
It likely packs in bits into an array of 32bit ints. You just can't allocate a few bits of space in any modern system.
Patrick
I'm not sure how much memory it takes. I do know sometimes I have to work with hardware that takes a single byte and uses the bits to represent various options, this is where I use the BitArray as it allows me to set each bit individually and then copy the result to a byte.
TimothyP
A: 

Did you try BitArray (System.Collections.BitArray)?

Otherwise you are not arbitrary - int+short is limited to.... 32 bits (length of int).

For anything shorter - take next longer primitive and just use it.

TomTom
+4  A: 

BitVector32 was designed with bit packing in mind (of course the structure you want to store has to fit on 32 bits).

See here and here for some examples

Ando
I need 6 bits, and exactly 6 bits. I have very large collections of data. My goal is to reduce memory by consuming only what I need.
Yaakov Davis
I had the impression you wanted to optimize the storage for a certain structure. In the light of your comment the closest thing to your requirements is a BitArray but that BitArray is meant for boolean logic and not at a substitute for a structure (you can still do this).Solving memory space optimizations using .net sounds very unnatural to me, a language closer to the operations system (e.g. C++) would seem more natural to me for this kind of tasks.
Ando
A: 

Ok, you must have meant 6 bytes of data. Then your math adds up ( int plus short is 6 bytes ).

As others have said, a collection would be best, but it seems like you have to pack everything into a struct.

The largest numeric type is the decimal and it's 128bits wide, while a long is 64. You can use those if you really, really what to keep that data on the stack and contiguous ( like it sounds you do ).

kervin
My math is wrong, my mistake :) I need 6 bits, that is, less than a byte. But for the sake of the question, is can be any other number of bits.
Yaakov Davis
+1  A: 

If you mean 6 bits, then a byte is enough to hold them as it has 8 bits.

public struct SixBits {

  private byte _data;

  private SixBits(byte value) {
    _data = value;
  }

  public SixBits ChangeBit(int index, bool value) {
    if (index < 0 || index > 5) throw new IndexOutOfRangeException();
    return new SixBits((byte)(_data & ~(1 << index) | ((value ? 1 : 0) << index)));
  }

  public bool this[int index] {
    get {
      if (index < 0 || index > 5) throw new IndexOutOfRangeException();
      return ((_data >> index) & 1) != 0;
    }
  }

}

If you mean 6 bytes, a long is enough to hold them as it has 8 bytes.

public struct SixBytes {

  private long _data;

  private SixBytes(long value) {
    _data = value;
  }

  public SixBytes ChangeByte(int index, byte value) {
    if (index < 0 || index > 5) throw new IndexOutOfRangeException();
    return new SixBytes(_data & ~(0xFFL << (index * 8)) | (long)value << (index * 8));
  }

  public byte this[int index] {
    get {
      if (index < 0 || index > 5) throw new IndexOutOfRangeException();
      return (byte)(_data >> (index * 8));
    }
  }

}

Unit test for the above structures:

SixBits x = new SixBits();
for (int i = 0; i < 6; i++) Assert.AreEqual(false, x[i]);
for (int i = 0; i < 6; i++) x = x.ChangeBit(i, true);
for (int i = 0; i < 6; i++) Assert.AreEqual(true, x[i]);
for (int i = 0; i < 6; i++) x = x.ChangeBit(i, false);
for (int i = 0; i < 6; i++) Assert.AreEqual(false, x[i]);
for (int i = 0; i < 6; i++) x = x.ChangeBit(i, (i & 1) == 0);
for (int i = 0; i < 6; i++) Assert.AreEqual((i & 1) == 0, x[i]);
for (int i = 0; i < 6; i++) x = x.ChangeBit(i, (i & 1) == 1);
for (int i = 0; i < 6; i++) Assert.AreEqual((i & 1) == 1, x[i]);

SixBytes y = new SixBytes();
for (int i = 0; i < 256; i++) {
  for (int j = 0; j < 6; j++) y = y.ChangeByte(j, (byte)i);
  for (int j = 0; j < 6; j++) Assert.AreEqual((byte)i, y[j]);
}
byte[] test = { 0, 1, 64, 2, 255, 3, 14, 32, 4, 96, 6, 254, 7, 12, 255, 128, 127 };
for (int i = 0; i < test.Length - 6; i++) {
  for (int j=0;j<6;j++) y = y.ChangeByte(j, test[i+j]);
  for (int j=0;j<6;j++) Assert.AreEqual(test[i+j], y[j]);
}
Guffa