Skip to content

Instantly share code, notes, and snippets.

@smorr
Last active June 27, 2016 09:50
Show Gist options
  • Save smorr/260f2f2edb9368a26835 to your computer and use it in GitHub Desktop.
Save smorr/260f2f2edb9368a26835 to your computer and use it in GitHub Desktop.
Using macros to box common structs (point, size, range, rect) in object-c
/* the following macros will create a mechanism to box common cocoa structures so can be easily added to NSArrays etc
*
* The macros can take multiple arguments allowing you to pass in an existing struct, or the components of the struct
*
* for example:
* NSValue * pointValue1 = @point(3,5); // pass in the two values that make up the point
*
* NSPoint * myPoint = NSMakePoint(3,5);
* NSValue * pointValue2 = @point(myPoint); // pass in a existing point.
*
* NSArray * frames = @[@rect([self frame]),@rect(10,10,50,50)];
*
* How this works...
*
* point(...) is a macro that that takes a variable number of arguments (but really should be 1 or 2 args for points)
* and will expand to one of two function calls depending on the number of arguments to the macro.
* valueFromPoint1_(NSPoint p) or
* valueFromPoint2_(CGFloat x, CGFloat y)
* these functions do the actual boxing (making an NSValue)
*/
#import <Foundation/Foundation.h>
// macros to deal with variable number of arguments to the boxing macros
#define PP_ARG_N( \
_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \
_11, _12, _13, _14, _15, _16, _17, _18, _19, _20, \
_21, _22, _23, _24, _25, _26, _27, _28, _29, _30, \
_31, _32, _33, _34, _35, _36, _37, _38, _39, _40, \
_41, _42, _43, _44, _45, _46, _47, _48, _49, _50, \
_51, _52, _53, _54, _55, _56, _57, _58, _59, _60, \
_61, _62, _63, N, ...) N
#define PP_RSEQ_N() \
62, 61, 60, \
59, 58, 57, 56, 55, 54, 53, 52, 51, 50, \
49, 48, 47, 46, 45, 44, 43, 42, 41, 40, \
39, 38, 37, 36, 35, 34, 33, 32, 31, 30, \
29, 28, 27, 26, 25, 24, 23, 22, 21, 20, \
19, 18, 17, 16, 15, 14, 13, 12, 11, 10, \
9, 8, 7, 6, 5, 4, 3, 2, 1, 0
#define PP_NARG_(...) PP_ARG_N(__VA_ARGS__)
#define PP_NARG(...) PP_NARG_(_, ##__VA_ARGS__, PP_RSEQ_N())
// macros to expand the base function name to append the number of args in the macro.
#define BOX_(a,b,...) a ## b ## _(__VA_ARGS__) // have to add an extra _
#define BOX(a,b,...) BOX_(a,b,__VA_ARGS__)
// the specific macros -- calling the BOX macro with the baseFunctionName, the number of args, and the arg list
//
// Not that it uses the YES?Macro:0 format to enable the @ prefix eg @point(1,2)
// the YES eats the @ -- the @YES will alway evaluate true so the first option is used. -- the second is not used ;
// techically format is not needed and you could get rid of the YES? ... :0 parts of the macro
// but then it would look like point(1,2) -- which doesn't look much like a box expression :)
//
#define point(...) YES?BOX(valueFromPoint, PP_NARG(__VA_ARGS__),__VA_ARGS__):0
#define rect(...) YES?BOX(valueFromRect, PP_NARG(__VA_ARGS__),__VA_ARGS__):0
#define size(...) YES?BOX(valueFromSize, PP_NARG(__VA_ARGS__),__VA_ARGS__):0
#define range(...) YES?BOX(valueFromRange, PP_NARG(__VA_ARGS__),__VA_ARGS__):0
// the actual boxing functions. Note that the name of the function is critical
// being the baseName (eg valueFromPoint) + number of arguments + _ the underscore is needed for the BOX_ macro to expand.
NSValue * valueFromPoint1_(NSPoint arg1){
return [NSValue valueWithPoint:arg1];
}
NSValue * valueFromPoint2_(double x, double y){
return [NSValue valueWithPoint:NSMakePoint(x, y)];
}
NSValue * valueFromSize1_(NSSize arg1){
return [NSValue valueWithSize:arg1];
}
NSValue * valueFromSize2_(double w, double h){
return [NSValue valueWithSize:NSMakeSize(w,h)];
}
NSValue * valueFromRange1_(NSRange arg1){
return [NSValue valueWithRange:arg1];
}
NSValue * valueFromRange2_(NSUInteger loc, NSUInteger len){
return [NSValue valueWithRange:NSMakeRange(loc,len)];
}
NSValue * valueFromRect1_(NSRect r){
return [NSValue valueWithRect:r];
}
NSValue * valueFromRect4_(double x, double y,double w, double h){
return [NSValue valueWithRect:NSMakeRect(x, y, w, h)];
}
// Example code
NSPoint pointFunc(){
return NSMakePoint(3,4);
}
int main(int argc, char *argv[]) {
@autoreleasepool {
NSArray * a = @[@point(1,2),
@point(2,3),
@point(pointFunc()),
@rect(10,10,50,50),
@range(10,30),
@size(5,7)];
NSLog (@"a: %@ ",a);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment