Last active
June 27, 2016 09:50
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* 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