Created
November 10, 2011 18:28
-
-
Save mikeash/1355671 to your computer and use it in GitHub Desktop.
Multiple return
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
// clang -W -Wall -Wno-unused-parameter -framework Foundation -fobjc-arc test.m | |
#import <Foundation/Foundation.h> | |
#define IDARRAY(...) ((id[]){ __VA_ARGS__ }) | |
#define IDCOUNT(...) (sizeof(IDARRAY(__VA_ARGS__)) / sizeof(id)) | |
typedef id (^Tuple)(int); | |
#define TUPLE(...) MakeTuple(IDARRAY(__VA_ARGS__), IDCOUNT(__VA_ARGS__)) | |
static const void *Retain(CFAllocatorRef allocator, const void *value) | |
{ | |
if(value) CFRetain(value); | |
return value; | |
} | |
static void Release(CFAllocatorRef allocator, const void *value) | |
{ | |
if(value) CFRelease(value); | |
} | |
CFStringRef CopyDescription(const void *value) | |
{ | |
return value ? CFCopyDescription(value) : CFSTR(""); | |
} | |
Boolean Equal(const void *a, const void *b) | |
{ | |
return CFEqual(a, b); | |
} | |
Tuple MakeTuple(const id *objs, unsigned count) | |
{ | |
CFArrayCallBacks cbs = { | |
0, | |
Retain, | |
Release, | |
CopyDescription, | |
Equal | |
}; | |
NSArray *array = CFBridgingRelease(CFArrayCreate(NULL, (void *)objs, count, &cbs)); | |
return ^(int x) { | |
NSCParameterAssert(x >= 0 && (unsigned)x < count); | |
return [array objectAtIndex: x]; | |
}; | |
} | |
@interface GetProxy : NSObject | |
- (void)addVariable: (void *)ptr; | |
@property (nonatomic, strong) id result; | |
@end | |
@implementation GetProxy { | |
CFMutableArrayRef _pointers; | |
} | |
@synthesize result; | |
- (id)init | |
{ | |
if((self = [super init])) | |
{ | |
_pointers = CFArrayCreateMutable(NULL, 0, NULL); | |
} | |
return self; | |
} | |
- (void)dealloc | |
{ | |
if(_pointers) | |
CFRelease(_pointers); | |
} | |
- (void)addVariable: (void *)ptr | |
{ | |
CFArrayAppendValue(_pointers, ptr); | |
} | |
- (void)setResult: (id)obj | |
{ | |
void objc_storeStrong(const void *, id); | |
Tuple tuple = obj; | |
for (CFIndex i = 0; i < CFArrayGetCount(_pointers); i++) | |
{ | |
const void *pointer = CFArrayGetValueAtIndex(_pointers, i); | |
objc_storeStrong(pointer, tuple(i)); | |
} | |
} | |
@end | |
#define FIRST(a, ...) a | |
#define SECOND(a, b, ...) b | |
#define REST(a, ...) __VA_ARGS__ | |
#define REST_PAIRS(a, b, ...) __VA_ARGS__ | |
#define MULTIPLY(x) x, x, x, x, x, x, x, x, x, x, x, x, x | |
#define MULTIPLY_PAIRS(x, y) x, y, x, y, x, y, x, y, x, y, x, y, x, y, x, y, x, y, x, y | |
#define FOREACH_HELPER5(macro, placeholderCheck, ...) macro(FIRST(__VA_ARGS__)) typedef char too_many_items_in_foreach_macro[placeholderCheck(SECOND(__VA_ARGS__)) ? 1 : -1]; | |
#define FOREACH_HELPER4(macro, placeholderCheck, ...) macro(FIRST(__VA_ARGS__)) FOREACH_HELPER5(macro, placeholderCheck, REST(__VA_ARGS__)) | |
#define FOREACH_HELPER3(macro, placeholderCheck, ...) macro(FIRST(__VA_ARGS__)) FOREACH_HELPER4(macro, placeholderCheck, REST(__VA_ARGS__)) | |
#define FOREACH_HELPER2(macro, placeholderCheck, ...) macro(FIRST(__VA_ARGS__)) FOREACH_HELPER3(macro, placeholderCheck, REST(__VA_ARGS__)) | |
#define FOREACH_HELPER(macro, placeholderCheck, ...) macro(FIRST(__VA_ARGS__)) FOREACH_HELPER2(macro, placeholderCheck, REST(__VA_ARGS__)) | |
#define FOREACH(macro, placeholderCheck, placeholder, ...) FOREACH_HELPER(macro, placeholderCheck, __VA_ARGS__, MULTIPLY(placeholder)) | |
#define FOREACH_PAIR_HELPER_CHECK(placeholderCheck, a, b, ...) { typedef char too_many_items_in_foreach_pair_macro[placeholderCheck(a, b) ? 1 : -1]; } | |
#define FOREACH_PAIR_HELPER5(macro, placeholderCheck, ...) macro(FIRST(__VA_ARGS__), SECOND(__VA_ARGS__)) FOREACH_PAIR_HELPER_CHECK(placeholderCheck, __VA_ARGS__) | |
#define FOREACH_PAIR_HELPER4(macro, placeholderCheck, ...) macro(FIRST(__VA_ARGS__), SECOND(__VA_ARGS__)) FOREACH_PAIR_HELPER5(macro, placeholderCheck, REST_PAIRS(__VA_ARGS__)) | |
#define FOREACH_PAIR_HELPER3(macro, placeholderCheck, ...) macro(FIRST(__VA_ARGS__), SECOND(__VA_ARGS__)) FOREACH_PAIR_HELPER4(macro, placeholderCheck, REST_PAIRS(__VA_ARGS__)) | |
#define FOREACH_PAIR_HELPER2(macro, placeholderCheck, ...) macro(FIRST(__VA_ARGS__), SECOND(__VA_ARGS__)) FOREACH_PAIR_HELPER3(macro, placeholderCheck, REST_PAIRS(__VA_ARGS__)) | |
#define FOREACH_PAIR_HELPER(macro, placeholderCheck, ...) macro(FIRST(__VA_ARGS__), SECOND(__VA_ARGS__)) FOREACH_PAIR_HELPER2(macro, placeholderCheck, REST_PAIRS(__VA_ARGS__)) | |
#define FOREACH_PAIR(macro, placeholderCheck, placeholder1, placeholder2, ...) \ | |
FOREACH_PAIR_HELPER(macro, placeholderCheck, __VA_ARGS__, MULTIPLY_PAIRS(placeholder1, placeholder2)) | |
#define PASS_ADDR(var) if(sizeof(var) == sizeof(id)) [__tempTupleGetProxy addVariable: &var]; | |
#define PLACEHOLDER_CHECK(x) (sizeof(x) == sizeof(char)) | |
#define GET(...) ({ \ | |
GetProxy *__tempTupleGetProxy = [[GetProxy alloc] init]; \ | |
FOREACH(PASS_ADDR, PLACEHOLDER_CHECK, (char){ 0 }, __VA_ARGS__) \ | |
__tempTupleGetProxy; }).result | |
#define DECLARE(type, var) type var; | |
#define PASS_ADDR_PAIR(type, var) PASS_ADDR(var) | |
#define PLACEHOLDER_CHECK_PAIR(type, var) (sizeof(var) == sizeof(char)) | |
#define PLACEHOLDER_CHECK_ALWAYS_TRUE(type, var) 1 | |
#define GETD(...) \ | |
FOREACH_PAIR(DECLARE, PLACEHOLDER_CHECK_ALWAYS_TRUE, , , __VA_ARGS__) \ | |
({ \ | |
GetProxy *__tempTupleGetProxy = [[GetProxy alloc] init]; \ | |
FOREACH_PAIR(PASS_ADDR_PAIR, PLACEHOLDER_CHECK_PAIR, , (char){ 0 }, __VA_ARGS__) \ | |
__tempTupleGetProxy; \ | |
}).result | |
Tuple Test(int x) | |
{ | |
if(x == 0) | |
return TUPLE(@"Hello", nil); | |
if(x == 1) | |
return TUPLE(nil, [NSError errorWithDomain: @"domain" code: 42 userInfo: nil]); | |
if(x == 2) | |
return TUPLE(@"Both!", [NSError errorWithDomain: @"domain" code: 42 userInfo: nil]); | |
if(x == 3) | |
return TUPLE(@"1", @"2", @"3", @"4"); | |
return TUPLE(@"1", @"2", @"3", @"4", @"5", @"6", @"7", @"8", @"9", @"10", @"11"); | |
} | |
int main (int argc, const char * argv[]) | |
{ | |
@autoreleasepool | |
{ | |
GETD(NSString *, str, NSError *, err) = Test(0); | |
NSLog(@"%@ %@", str, err); | |
GET(str, err) = Test(1); | |
NSLog(@"%@ %@", str, err); | |
GET(str, err) = Test(2); | |
NSLog(@"%@ %@", str, err); | |
GETD(NSString *, a, NSString *, b, NSString *, c, NSString *, d) = Test(3); | |
NSLog(@"%@ %@ %@ %@", a, b, c, d); | |
GET(a, b) = Test(3); | |
NSLog(@"%@ %@", a, b); | |
// id o1, o2, o3, o4, o5, o6, o7, o8, o9, o10, o11; | |
// GETD(id, o1, id, o2, id, o3, id, o4, id, o5, id, o6, id, o7, id, o8, id, o9, id, o10, id, o11) = Test(4); | |
// GET(o1, o2, o3, o4, o5, o6, o7, o8, o9, o10, o11) = Test(4); | |
// NSLog(@"%@ %@ %@ %@ %@ %@ %@ %@ %@ %@ %@", o1, o2, o3, o4, o5, o6, o7, o8, o9, o10, o11); | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This really is just plain crazy.