How do those bitmasks actually work?

For example, this method from NSCalendar takes a bitmask:

- (NSDate *)dateByAddingComponents:(NSDateComponents *)comps toDate:(NSDate *)date options:(NSUInteger)opts

So options can be like:

NSUInteger options = kCFCalendarUnitYear;

or like:

NSUInteger options = kCFCalendarUnitYear | kCFCalendarUnitMonth | kCFCalendarUnitDay;

What I don't get is, how is this actually done? I mean: How can they pull out those values which are merged into options? If I wanted to program something like this, that can take a bitmask, how would that look?

Answers


To do this, you want to bitwise AND the value you're testing against the mask, then see if the result of the ANDing equals the mask itself:

if ((options & kCFCalendarUnitYear) == kCFCalendarUnitYear) {
   // do whatever
}

Bitmasks are pretty basic really. You can think of it like this (C# until somebody can convert):

public enum CalendarUnits
{
    kCFCalendarUnitDay = 1, // 001 in binary
    kCFCalendarUnitMonth = 2, // 010 in binary
    kCFCalendarUnitYear = 4, // 100 in binary
}

You can then use the bitwise operators to combine the values:

// The following code will do the following
// 001 or 100 = 101
// So the value of options should be 5
NSUInteger options = kCFCalendarUnitDay | kCFCalendarUnitYear;

This technique is also often used in security routines:

public enum Priveledges
{
    User = 1,
    SuperUser = 2,
    Admin = 4
}

// SuperUsers and Admins can Modify
// So this is set to 6 (110 binary)
public int modifySecurityLevel = SuperUser | Admin;

Then to check the security level, you can use the bitwise and to see if you have sufficient permission:

public int userLevel = 1;
public int adminLevel = 4;

// 001 and 110 = 000 so this user doesn't have security
if(modifySecurityLevel & userLevel == userLevel)

// but 100 and 110 = 100 so this user does
if(modifySecurityLevel & adminLevel == adminLevel)
    // Allow the action

Bitmasks work because in binary, each power of 2 (i.e., 20=1, 21=2, 21=4) occupies a single spot in the sequence of bits. For example:

decimal | binary 
1       | 0001
2       | 0010
4       | 0100
8       | 1000

When you or (the operator | in C-like languages) two numbers a and b together into c, you're saying "take the bits that are in a, b, or both and put them in c." Since a power of two represents a single position in a binary string, there's no overlap, and you can determine which ones were set. For example, if we or 2 and 4

0010 | 0100 = 0110

Notice how it basically combined the two. On the other hand, if we or 5 and 3:

decimal | binary 
5       | 0101
3       | 0011

0101 | 0011 = 0111

notice that we have no way of telling which bits came from where, because there was overlap between the binary representation of each.

This becomes more apparent with one more example. Let's take the numbers 1, 2, and 4 (all powers of two)

0001 | 0010 | 0100 = 0111

This is the same result as 5 | 3! But since the original numbers are powers of two, we can tell uniquely where each bit came from.


The key is remembering that each one of those values you merge into "options" is really just a number. I'm not sure how familiar you are with binary, but you can think of it in decimal and just add numbers rather than ORing them.

Let's say A=10, B=100, and C=1000

If you wanted to set options = A+B, then options would equal 110. The method you called would then look at the "tens" place for A, the "hundreds" place for B, and the "thousands" place for C. In this example, there is a 1 is the hundreds place and the tens place, so the method would know that A and B were set in the options.

It's a little different since computers use binary not decimal, but I think the idea is very similar, and sometimes it's easier to think about it in a familiar numbering system.


typedef NS_OPTIONS(NSUInteger, MyOption)
{
   OptionNone = 0,
   OptionOne = 1 << 0,
   OptionTwo = 1 << 1,
   OptionThree = 1 << 2
};

if (givenValue & OptionOne) {
   // bit one is selected
}

if (givenValue & OptionTwo) {
   // bit two is selected
}

http://en.wikipedia.org/wiki/Mask_(computing)


I've found Calculator.app to be helpful in visualizing bit masks. (Just choose View > Programmer, and then click the button to Show Binary). (You can click on any of the 0s or 1s in the binary table to switch those bits on or off; or, enter numbers in decimal or hex (use the 8 | 10 | 16 NSSegmentedControl to switch between different representations)).


Need Your Help

How to use warp-tls instead of warp with scotty?

haskell scotty haskell-warp

I need to start my scotty application with warp-tls instead of plain warp server but is seems running warp is hardwired in scotty's source code. Am I missing something obvious?