Index Set Foreach
Download
- MFIndexSetForeach 1.0 (2 Kb)
- First release. December 12 2011.
Introduction
Index sets can be a little annoying in Objective-C. Unlike arrays, sets, and dictionaries, you can’t iterate over them using a straightforward for (a in b)
loop. That’s because unlike other Objective-C containers, index sets contains integers, not objects.
Since Mac OS X 10.6 you can use a block to iterate over an index set, but this isn’t always ideal: breaking out of the loop is more complicated, and returning from the block doesn’t return from the outer function.
In an ideal world you could write this and it’d work, but alas it doesn’t:
for (NSUInteger index in indexSet)
{
// loop body
}
What MFIndexSetForeach
achieves using some macro wizardry is this:
MFIndexSetForeach(index, indexSet)
{
// loop body
}
MFIndexSetForeach
iterates over all indexes in a set. It uses the getIndexes:maxCount:inIndexRange:
method of NSIndexSet
to fill a small buffer of indexes, iterates over the buffer then refills the buffer and continue iterating until all indexes have been iterated over. This is quite similar to how for (a in b)
works.
This loop behaves in every way like you’d expect a loop to behave: you can break
from it, you can continue
in it, and if you return
it’ll truly return from the function:
MFIndexSetForeach(index, indexSet)
{
if (index % 33) continue;
if (index % 22) break;
if (index % 11) return YES;
}
Oh, and the braces are optional too.
Have fun with it.
How to Use
MFIndexSetForeach
is a macro in a header file of the same name. Just add the “MFIndexSetForeach.h” file to your project, then in the file where you need a loop write:
#import "MFIndexSetForeach.h"
You’re all set.
How does it work?
The equivalent generated code would look somewhat like this:
NSRange _indexRange = NSMakeRange(0, NSUIntegerMax);
for (NSUInteger index,
_bufferIndex = _bufferLength-1,
_indexCount = 0,
_indexBuffer[_bufferLength];
_MFIndexSetForeachNextIndex(
&_bufferIndex, &_indexCount, indexSet, _indexBuffer,
_bufferLength, &_indexRange, &index);
)
{
if (index % 33) continue;
if (index % 22) break;
if (index % 11) return YES;
}
where, _MFIndexSetForeachNextIndex
is a short inline function doing all the work. The true generated code will look a little more cryptic since variable names are generated in a way that avoids clashes.
License
MFIndexSetForeach is available under the terms of the Boost Software License 1.0.
History
Index Set Foreach 1.0
- Initial release.