Using a Bitmask in C#

Using a bitmask in C#

The traditional way to do this is to use the Flags attribute on an enum:

[Flags]
public enum Names
{
None = 0,
Susan = 1,
Bob = 2,
Karen = 4
}

Then you'd check for a particular name as follows:

Names names = Names.Susan | Names.Bob;

// evaluates to true
bool susanIsIncluded = (names & Names.Susan) != Names.None;

// evaluates to false
bool karenIsIncluded = (names & Names.Karen) != Names.None;

Logical bitwise combinations can be tough to remember, so I make life easier on myself with a FlagsHelper class*:

// The casts to object in the below code are an unfortunate necessity due to
// C#'s restriction against a where T : Enum constraint. (There are ways around
// this, but they're outside the scope of this simple illustration.)
public static class FlagsHelper
{
public static bool IsSet<T>(T flags, T flag) where T : struct
{
int flagsValue = (int)(object)flags;
int flagValue = (int)(object)flag;

return (flagsValue & flagValue) != 0;
}

public static void Set<T>(ref T flags, T flag) where T : struct
{
int flagsValue = (int)(object)flags;
int flagValue = (int)(object)flag;

flags = (T)(object)(flagsValue | flagValue);
}

public static void Unset<T>(ref T flags, T flag) where T : struct
{
int flagsValue = (int)(object)flags;
int flagValue = (int)(object)flag;

flags = (T)(object)(flagsValue & (~flagValue));
}
}

This would allow me to rewrite the above code as:

Names names = Names.Susan | Names.Bob;

bool susanIsIncluded = FlagsHelper.IsSet(names, Names.Susan);

bool karenIsIncluded = FlagsHelper.IsSet(names, Names.Karen);

Note I could also add Karen to the set by doing this:

FlagsHelper.Set(ref names, Names.Karen);

And I could remove Susan in a similar way:

FlagsHelper.Unset(ref names, Names.Susan);

*As Porges pointed out, an equivalent of the IsSet method above already exists in .NET 4.0: Enum.HasFlag. The Set and Unset methods don't appear to have equivalents, though; so I'd still say this class has some merit.


Note: Using enums is just the conventional way of tackling this problem. You can totally translate all of the above code to use ints instead and it'll work just as well.

Storing multiple values via bitmask in c#

Without a more specific question, and in particular you showing the code you have so far and explaining what you're having trouble specifically in terms of getting it to work, it's hard to know exactly what the best answer would be.

That said, here are a couple of example methods that might get you pointed in the right direction:

// Stores the given value in storage at the given index
int Set(int storage, int value, int index)
{
int shiftCount = index * 5,
mask = 0x1f << shiftCount;

return (storage & ~mask) | (value << shiftCount);
}

// Retrieves the value stored in storage at the given index
int Get(int storage, int index)
{
int shiftCount = index * 5,
mask = 0x1f << shiftCount;

return (storage & mask) >> shiftCount;
}

The Set() method above takes the current value in storage, clears all of the bits in the range of bits where you want to store your five-bit value, and then uses the | operator to store that five-bit value, shifting the bits of that value to the right place first.

The Get() method performs the reverse operation. It masks off (clears) all of the bits not in the range of bits where the value was stored, and then shifting the stored bits down to the least-significant five bits of an int before returning that result.

Notes:

  • The above is specific to your stated problem. It could easily be generalized by encapsulating in a class where the bit count can be configured at initialization and the mask is generated based on that bit count rather than being hard-coded.
  • There is no error-checking in the above code. In a production-code version, it would be much better to verify that the value passed to the Set() method does in fact fit in five bits (i.e. is less than 0x20).

EDIT:

Here is a simple console program that demonstrates the use of the above, with your example data:

static void Main(string[] args)
{
int[] array = { 31, 6, 23, 31 };
int storage = 0;

storage = ArrayToStorage(array, storage);

Console.WriteLine(storage);
LogArray(array);

storage = Set(storage, 9, 1);
storage = Set(storage, 17, 2);

StorageToArray(array, storage);

Console.WriteLine(storage);
LogArray(array);
}

static int ArrayToStorage(int[] array, int storage)
{
for (int i = 0; i < array.Length; i++)
{
storage = Set(storage, array[i], i);
}

return storage;
}

static void StorageToArray(int[] array, int storage)
{
for (int i = 0; i < array.Length; i++)
{
array[i] = Get(storage, i);
}
}

static void LogArray(int[] array)
{
Console.WriteLine("[" + string.Join(", ", array) + "]");
}

// Stores the given value in storage at the given index
static int Set(int storage, int value, int index)
{
int shiftCount = index * 5,
mask = 0x1f << shiftCount;

return (storage & ~mask) | (value << shiftCount);
}

// Retrieves the value stored in storage at the given index
static int Get(int storage, int index)
{
int shiftCount = index * 5,
mask = 0x1f << shiftCount;

return (storage & mask) >> shiftCount;
}

How do I check, if bitmask contains bit?

well

if (8 & bitmask == 8 ) {
}

will check if the bitmask contains 8.

more complex

int mask = 8 | 12345;
if (mask & bitmask == mask) {
//true if, and only if, bitmask contains 8 | 12345
}

if (mask & bitmask != 0) {
//true if bitmask contains 8 or 12345 or (8 | 12345)
}

may be interested by enum and more particularly FlagsAttibute.

Decoding a bitmask from a value in C#

What about one-liner?

var mask = (Amenities)5722635;

var result =
Enum.GetValues(typeof(Amenities))
.Cast<Amenities>()
.Where(value => mask.HasFlag(value))
.ToList();

You can cache result of Enum.GetValues(typeof(Amenities)).Cast<Amenities>() in order to improve performance.

Bit manipulation in C# using a mask

It seems like you want:

(orig & ~mask) | (input & mask)

The first half zeroes the bits of orig which are in mask. Then you do a bitwise OR against the bits from input that are in mask.

Determining values in a bitmask

bit 9 is 256; bit 10 is 512; bit 13 is 4096.

So:

if((val & 256) != 0) { /* bit 9 is set */ }
if((val & 512) != 0) { /* bit 10 is set */ }
if((val & 4096) != 0) { /* bit 13 is set */ }

You could also use an enum for convenience:

[Flags]
public enum MyFlags {
None = 0,
Foo = 1,
Bar = 2,
...
SomeFlag = 256,
AnotherFlag = 512,
...
}

then:

MyFlags flags = (MyFlags)val;
if((flags & MyFlags.SomeFlag) != 0) {/* SomeFlag is set */}

And likewise:

MyFlags thingsWeWant = MyFlags.Foo | MyFlags.SomeFlag | MyFlags.AnotherFlag;
int val = (int)thingsWeWant;

Using Bitmask to read first 2 bits of a ushort in C#

You can shift these bits to have them being the rightmost ones and then mask with 0b11:

 // drop all bits except topmost ones 16 - 14 == 2 which are now the rightmost
int bits = (rawData[i] >> 14) & 0b11;

if (bits == 0b11) {
// Both bits are set
}

To clear these bits you use XOR ^ (since 1 ^ 1 == 0):

 int mask = 0b11 << 14;

// remove 14th and 15th set bits
rawData[i] = (ushort)(rawData[i] ^ mask);

Let's combine these parts:

 if (((rawData[i] >> 14) & 0b11) == 0b11)
rawData[i] = (ushort)(rawData[i] ^ (0b11 << 14));

Finally, the method can be

public static void trimData(ushort[] rawData) {
if (rawData is null)
throw new ArgumentNullException(nameof(rawData));

for (int i = 0; i < rawData.Length; i++)
if (((rawData[i] >> 14) & 0b11) == 0b11)
rawData[i] = (ushort)(rawData[i] ^ (0b11 << 14));
}


Related Topics



Leave a reply



Submit