bitarray to byte array possible endian issues

240 Views Asked by At

I am wanting to store a sequence of bool values in azure blob storage along with a separate map file (a comma separated list of names in the same order as the bool values).

As efficiency and storage are important factors I want to store the bool values as a byte array.

I have gone about this by constructing a bitarray, i am then using the bitarray CopyTo to copy it into a byte array. I have tested locally by converting it back with new BitArray(mybytearray) and comparing the result and it matches fine.

My question is, is this code going to be reliable? or will it be environment/hardware specific? do big/little endians come into effect here? when i deploy this to an azure service running on windows will it operate the same? would running off a linux vm cause the endianess to create wrong outputs? (a separate azure service will actually be the one reading from the blob but it should be configured the same i.e windows/plan)

I am a bit confused, while my code seems to be working fine, the below SO post accepted answer has comments saying that the way bitarray writes to bytearray the order will be reversed, so you should specifically reverse the array before putting it into the bytearray. Convert from BitArray to Byte

This is a minimal code example of my logic (my case has hundreds of thousands of booleans):

     var boolarr = new bool[] { true, true, false, false, false };
            var bitarr = new BitArray(boolarr);
            var length = bitarr.Length / 8;
            if (bitarr.Length % 8 > 0)
                length += 1;
            var bytearray = new byte[length];
            bitarr.CopyTo(bytearray, 0);
            BitArray bits = new BitArray(bytearray);

//Below just checking the above is working properly
            for (var i = 0; i < bits.Length; i++)
            {
                if (i >= bitarr.Length)
                    break;//last byte may not be using all bits
                if (bits[i] != bitarr[i])
                {
                    throw new Exception();//This would be bad.
                }
            }

1

There are 1 best solutions below

0
Nigel On

I think the code will be hardware specific, but to be honest, I don't know the inner workings of BitArray and I can't tell you for sure. But I can give you some code that will work regardless of the hardware/environment:

private const int bitsPerByte = 8;
public static byte[] ToByteArray(bool[] bits)
{
    var bitCount = bits.Length;
    var byteCount = bitCount / bitsPerByte ;
    if (bitCount - byteCount*bitsPerByte  > 0) byteCount += 1;
    var bytes = new byte[byteCount];
    for (int i = 0; i < bitCount; i++)
    {
        SetBit(bytes, i, bits[i]);
    }

    return bytes;
}

public static bool[] ToBoolArray(byte[] bytes)
{
    var bitCount = bytes.Length * bitsPerByte;
    var bools = new bool[bitCount];
    for (int i = 0; i < bitCount; i++)
    {
        bools[i] = GetBit(bytes, i);
    }

    return bools;
}

This relies on the following helper code:

private static bool GetBit(byte[] bytes, int bitNumber)
{
    var byteNumber = bitNumber / bitsPerByte;
    var bit = bitNumber % bitsPerByte;
    return GetBit(bytes[byteNumber], bit);
}

private static bool GetBit(byte byteValue, int bitNumber) => (byteValue >> bitNumber) % 2 > 0;

private static void SetBit(byte[] bytes, int bitNumber, bool value)
{
    var byteNumber = bitNumber / bitsPerByte;
    var bit = bitNumber % bitsPerByte;
    SetBit(ref bytes[byteNumber], bit, value);
}

private static void SetBit(ref byte byteValue, int bitNumber, bool value)
{
    var operand = (byte)(1 << bitNumber);
    if (value)
    {
        byteValue |= operand;
    }
    else
    {
        operand = (byte)~operand;
        byteValue &= operand;
    }
}