2

I'm trying to extend this topic a bit by expanding it to cover 5-bit values packed into a byte[] data structure.

The specific objective I'm trying to achieve would be to store a total of 128 5-bit (0-31) numeric values in a 80-byte array with a get/set function to access and manipulate the values within the array.

Does anyone have experience with this?

Edit:

Thanks to Guffa in the accepted answer below, here's an inline version of his class for use in static calls:

byte Get_5_In_BA(ref byte[] storage, int index)
{
    int bigIndex = (index * 5) / 8;
    int smallIndex = (index * 5) % 8;
    if (smallIndex > 3)
    {
        return ((byte) (((storage[bigIndex] + (storage[bigIndex + 1] * 0x0100)) >> smallIndex) & 0x1F));
    }
    return ((byte) ((storage[bigIndex] >> smallIndex) & 0x1F));
}

void Set_5_In_BA(ref byte[] storage, int index, byte value)
{
    if (value > 31) { value = 31; }
    int bigIndex = (index * 5) / 8;
    int smallIndex = (index * 5) % 8;
    int mask = 0x1F << smallIndex;
    storage[bigIndex] = (byte) ((storage[bigIndex] & ~mask) | (value << smallIndex));
    if (smallIndex > 3)
    {
        storage[bigIndex + 1] = (byte) ((storage[bigIndex + 1] & ~(mask >> 8)) | (value >> (8 - smallIndex)));
    }
}
Community
  • 1
  • 1
CoryG
  • 2,429
  • 3
  • 25
  • 60
  • The data I'm trying to pack into it is 5 bits in length so it seems like there would a lot of wasted space (37.5%) unless I'm missing something. – CoryG Apr 12 '15 at 20:00
  • You shouldn't use `ref` on the `storage` parameters. You would only use that if you wanted to replace the entire array object with another array object in the method. – Guffa Apr 12 '15 at 20:52

1 Answers1

4

Something like this should do it:

public class FiveBit {

  private byte[] _data;

  public FiveBit(int len) {
    _data = new byte[(len * 5 + 7) / 8];
  }

  public int this[int index] {
    get {
      int i = index * 5 / 8;
      int ofs = index * 5 % 8;
      if (ofs > 3) {
        return ((_data[i] + _data[i + 1] * 256) >> ofs) & 31;
      } else {
        return (_data[i] >> ofs) & 31;
      }
    }
    set {
      int i = index * 5 / 8;
      int ofs = index * 5 % 8;
      int mask = 31 << ofs;
      _data[i] = (byte)((_data[i] & ~mask) | (value << ofs));
      if (ofs > 3) {
        _data[i + 1] = (byte)((_data[i + 1] & ~(mask >> 8)) | (value >> (8 - ofs)));
      }
    }
  }

}

Note: This is not throroughly tested, but I have tested that I can put 128 random 5-bit values in it, and get the same values out again. You should also add some range checks on the parameters to make the code more robust, and I didn't give much thought to the class name so you can surely make up something that describes it better.

Guffa
  • 687,336
  • 108
  • 737
  • 1,005