jimbo
jimbo

Reputation: 611

Faster way to apply a bit mask while working with strings and shorts?

I have the following bit of code which will take in a string of words as well as a bit-mask. It will apply the mask to a certain chunk of a certain word (as specified by startWord, highBit and length) and then return a true or false value if the mask matches.

It works, but it's not very quick. Surely there's a way of doing it better?

EDIT:

To clarify, highBit and length are used to shorten the length of the word. So if we have a word that is dec: 37, then the binary is 0b100101. If it has a high bit of 2 and a length of two, then we only care about applying the mask to the last two digits (01). If it had a high bit of 3 and a length of 2, then it would be the digits in the square brackets: 0b100[10]1 etc.

It's effectively checking that any bit that is set in the mask is also set in the corresponding word at the corresponding position.

Further Edit:

If we have word 37 (0b100101) and a mask of (0b1), and we're interested in the entire word (so high bit is 15, and length is 16) then this will evaluate true. If the mask is 0b0 then it will also evaluate true (We are just looking for bits that are set).

The mask should always be greater in length than the "length" of the section of the word being analysed.

  public bool AddMask(string maintMessage, short mask, int startWord, int highBit, int length)
    {            
        // Maintenance message is a string of decimal 16-bit values 
        // seperated by semi-colons.
        var splitMsg = maintMessage.Split(';');
        var word = splitMsg[startWord];
        return AddMask(short.Parse(word), mask, highBit, length);            
    }


    public bool AddMask(short wordToMask, short mask, int highBit, int length)
    {

        if (highBit < length)
            length = highBit; // Or throw an exception?

        var binWord = Convert.ToString(wordToMask, 2);
        if (length > binWord.Length) // Shorten 'length' to max possible length
            length = binWord.Length;

        binWord = binWord.Substring(binWord.Length - highBit, length);

        var shortWord = Convert.ToInt16(binWord, 2);

        var result = shortWord & mask;
        return result == mask;
    }

Upvotes: 1

Views: 2674

Answers (1)

Peter Duniho
Peter Duniho

Reputation: 70671

If I understand correctly, what you are really saying is that the method should return true if and only if each bit in the wordToMask value is set in the corresponding location where the same bit is set in the mask, with the qualification that the mask value should be aligned with the group of bits to be checked.

If so, then your problem comes down to something as simple as this:

bool AddMask(short wordToMask, short mask, int highBit, int length)
{
    return mask == ((wordToMask >> (highBit - length)) & mask);
}

In other words, shift the original data to the right so that the bits to be checked start at 0 – i.e. are aligned with the mask – then perform a bit-wise & and see if the result is the same as the mask. If any of the bits in the mask weren't set in the wordToMask, they will get set to 0 and the result won't match. Otherwise, it will.

I should note that it's somewhat unconventional to number the bits starting at 1. Like arrays, bits are typically indexed starting at 0. But the above matches your description; e.g. if highBit is 2 and the length is 2, you say you want to consider only the two lowest bits.

The above also assumes that the mask won't have bits set where they don't matter. If that's not the case, then you would have to add a little more code to mask off the higher bits you want to ignore. That would look more like this:

bool AddMask(short wordToMask, short mask, int highBit, int length)
{
    // Shift the word to align with the mask
    short result = (short)(wordToMask >> (highBit - length)),
        resultMask = (short)((1 << highBit) - 1);

    // Clear all the bits higher than highBit
    result &= resultMask;

    // Compare with the mask
    return (resultMask & mask) == (result & mask);
}

Upvotes: 1

Related Questions