Ad

Our DNA is written in Swift
Jump

Bit Masks

Joseph Collins asks:

How do you decipher a bit mask from an argument which logically OR’d multiple values together? Enum uses bit shifting.

This question came to me while looking at UIView’s header file and wondering how Apple handles the animation options bitmask.

If you have several modes of something then usually you get by with an emum. But if you can combine several flags in s single value then you have to do this by means of bit masks. Let’s explore these today.

An enum is basically just a number, an integer. But you are telling the compiler that the individual values are legal values. Internally the first value will be 0, the second will be 1 and so on. If you want the first value to be a different value you can specify this and you can even specify a different number for each value. If you don’t, then they are just numbered sequentially.

Here’s an example from UIView.h:

typedef enum {
    UIViewAnimationCurveEaseInOut,         // slow at beginning and end
    UIViewAnimationCurveEaseIn,            // slow at beginning
    UIViewAnimationCurveEaseOut,           // slow at end
    UIViewAnimationCurveLinear
} UIViewAnimationCurve;

This defines UIViewAnimationCurveEaseInOut as 0 and the other values as 1, 2 and 3 using the automatic numbering. Often a developer chooses the default value to be the first because then a property using this type is also automatically initialized with the first value, aka 0.

From the same header file we can glean another example. Still defined as an enum, but using a bit mask:

enum {
    UIViewAutoresizingNone                 = 0,
    UIViewAutoresizingFlexibleLeftMargin   = 1 << 0,
    UIViewAutoresizingFlexibleWidth        = 1 << 1,
    UIViewAutoresizingFlexibleRightMargin  = 1 << 2,
    UIViewAutoresizingFlexibleTopMargin    = 1 << 3,
    UIViewAutoresizingFlexibleHeight       = 1 << 4,
    UIViewAutoresizingFlexibleBottomMargin = 1 << 5
};
typedef NSUInteger UIViewAutoresizing;

This is actually doing what I told you above, setting individual values for the numbers of the enum. The first value is 0, the second is a 1 bit shifted to the left by 0 positions, i.e. 1. The third value is a 1 bit shifted to the left by 1 positions, i.e. 2. The fourth is a 1 bit shifted to the left by 2 positions, i.e. 4. Get it it? They could have written out the numbers like this, but a geeky engineer preferred to write the values as shifts, number << bits_to_shift. There's another interesting fact to be seen there. Usually you would typedef an enum and call that type something of your own. Then you would use this type for defining your properties. Apple actually does not give the enum (typedef keyword omitted) a name. But actually they define a type UIViewAutoresizing to be an unsigned integer. Isn't that a bit weird because it breaks the compile-time type checking? To understand working with bits we need to review a couple of operators in the C language.

  • logical OR: a || b
  • logical NOT: !a
  • logical AND: a && b
  • bitwise OR: a | v
  • bitwise NOT: ~a
  • bitwise AND:  a & b
  • bitwise shift left: a << b
  • bitwise shift right:  a >> b

One thing that tends to confuse people is the distinction between “logical” and “bitwise”.  You probably have used the logical operators quite a bit in if statements. Think of the bitwise cousins of essentially the same but not just for one and zero, but for all bits of a number. A logical NOT of 5 is 0, but a bitwise NOT of 5 (bin 101) is 2 (bin 010).

To put it in simpler terms, a NOT flips all ones to zeros and vice versa. The AND and OR are twice the character for logical and once for bitwise. OR means that one of the bits needs to be one for the result to also be one. AND means that both need to be one for the result to be one. Remember that.

To combine several values from a bit mask enum into one, you simply chain them together with the pipe symbol, which is the bitwise OR operator. Mathematically a bitwise OR is the same as an addition of the values, as long as they don’t overlap.

view.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;

Now if you want to use a bit mask in your own code would involve the above mentioned type definitions as well as an if to check if certain bits of this mask are set. The simplest method I know is to basically make use of the logical AND. If the result is not equal to 0 – which it is if the bit was set – then we know that this bit was set.

if (view.autoresizingMask & UIViewAutoresizingFlexibleWidth)
{
   // bit was set
}

You could also compare the result to != 0, greater than 0 or equal to the value you are checking for but personally I think that this version is the most readable. Let me repeat that bit masks only work if you have non-overlapping numbers in the enum. Each flag needs to be a distinct bit in the number, otherwise you end up with unexpected result. Adding values to it that are not single bits would set multiple flags at the same time.

And then there’s the “pro” option. If you need to have more than a single bit on or off, but actually want to have an enum in and enum, there is also a way to do that as you can see in UIViewAnimationOptions. This is really weird to mentally parse if you are seeing that for the first time.

enum {
    UIViewAnimationOptionLayoutSubviews            = 1 <<  0,
    UIViewAnimationOptionAllowUserInteraction      = 1 <<  1, // turn on user interaction while animating
    UIViewAnimationOptionBeginFromCurrentState     = 1 <<  2, // start all views from current value, not initial value
    UIViewAnimationOptionRepeat                    = 1 <<  3, // repeat animation indefinitely
    UIViewAnimationOptionAutoreverse               = 1 <<  4, // if repeat, run animation back and forth
    UIViewAnimationOptionOverrideInheritedDuration = 1 <<  5, // ignore nested duration
    UIViewAnimationOptionOverrideInheritedCurve    = 1 <<  6, // ignore nested curve
    UIViewAnimationOptionAllowAnimatedContent      = 1 <<  7, // animate contents (applies to transitions only)
    UIViewAnimationOptionShowHideTransitionViews   = 1 <<  8, // flip to/from hidden state instead of adding/removing
 
    UIViewAnimationOptionCurveEaseInOut            = 0 << 16, // default
    UIViewAnimationOptionCurveEaseIn               = 1 << 16,
    UIViewAnimationOptionCurveEaseOut              = 2 << 16,
    UIViewAnimationOptionCurveLinear               = 3 << 16,
 
    UIViewAnimationOptionTransitionNone            = 0 << 20, // default
    UIViewAnimationOptionTransitionFlipFromLeft    = 1 << 20,
    UIViewAnimationOptionTransitionFlipFromRight   = 2 << 20,
    UIViewAnimationOptionTransitionCurlUp          = 3 << 20,
    UIViewAnimationOptionTransitionCurlDown        = 4 << 20,
    UIViewAnimationOptionTransitionCrossDissolve   = 5 << 20,
    UIViewAnimationOptionTransitionFlipFromTop     = 6 << 20,
    UIViewAnimationOptionTransitionFlipFromBottom  = 7 << 20,
};
typedef NSUInteger UIViewAnimationOptions;

I’m not dyslexic, but initially I thought “WTF are they doing shifting the number 20 (bin 10100) to the left?”. So you’re forgiven if you have the same reaction.

The first block is as we discussed before. The second and third block are actually more than single bits. You need two bits to represent the values 0 through 3. And three bits for 0 through 7. So here Apple is simply using the values and shifts them into place, 16 or 20 bits respectively. The advantage here is that a single animation options bit mask offers 32 bits that can be used. Packing the transition and the curve values into this still leaves with with a single integer to pass around.

Inside the UIKit code you probably have something like this, which shifts the values back to the right edge and then masks it and then compares.

NSUInteger transition = (animationOption >> 20) & 7;
NSUInteger curve = (animationOption >> 16) & 3;

The bitwise AND serves to mask out other set bits. Though if you are bit shifting the leftmost slot to the right, then the “incoming bits” are all zeroed anyway. But it’s probably a smart idea to make this masking a habit.

When creating your own bit masks I suggest that you name them in a similar way prefixing all enum values the same. This causes them to appear together in autocompletion and groups them logically.

Did you know you can actually also specify binary and hexadecimal values directly in your code? For hex numbers you add prefix 0x for binary prefix 0b. I heard that some compilers don’t know the binary prefix, but ours (LLVM) does. So if you EVER find yourself needing that you can use it. (You probably never will.)

NSUInteger b = 0b101; // binary
NSUInteger h = 0xAA; // hex

If you only take one thing away from this article then it should be the distinction between “logical” and “bitwise”. Because then you would also know what is wrong in the original question. Can you spot it?

Image “bitmask {phantom of the opera}” by S.D. Hilderbrand


Categories: Q&A

5 Comments »

  1. Great post! Problem in the question is that I should of stated that they used bitwise OR. And the problem in your post is you should have stated that you used bitwise AND. And it is a very simple method! I like it! But I still have a few more questions on the pro method.

    1. I still don’t completely understand the second and third blocks shifting over 16 and 20 respectively.

    Would it be safe to say that for options that can be set together, use the form 1 << n? And options that only one should be chosen, use the form n <> 16) & 3;

    does & 3 take care of all the possible transition values? So that you are only left with a possible curve value?

    I guess if you are not careful you would lose bits, and end up with a completely different value.

    3. And then I am guessing you would compare in an if statement:
    If (curve == UiViewAnimationOptionCurveEaseOut)

    Or you could possibly use a switch statement, atleast for the blocks shifted over by the same amount.

    For the first block where multiple options can be set you would still test in an if statement using a bitwise AND.
    If (animationOption & UIViewAnimationOptionRepeat)

    Thank you for all your help! Especially since I have searched all over the Internet and this has been the best explanation I have received yet!

    – Joe

  2. The 3 and 7 in the pro example are because they are 0b11 and 0b111 respectively. They are simply preserving the bits that you are interested in while (together with the AND) setting all other bits to 0.

    Careful with a comparison though. I just realized that instead of shifting the value to the right and then masking it it would be smarter to left shift the masking bits. Then a switch or if would work for comparing with the original enum values. But the point really was that by means of shifting and masking you get the actual (zero-based) value for this part.

  3. Thank you for the article.

    I just was sidetracked a bit by your statement:
    ` a bitwise NOT of 5 (bin 101) is 2 (bin 010).`

    What happened with the leading zero’s? (5 = 0000 0101, right? Or for an unsigned int 29 zero’s and then 101)

    So shouldn’t ~5 be an enormously big number?

    Thanks,
    Dirk

  4. Perfect! Exactly the kind of information I needed, I have been scratching my head over those weird enums, but now I know why they define them as bit shifts, thank you!