Skip to content

Instantly share code, notes, and snippets.

@mikeash
Created November 10, 2011 18:28
Show Gist options
  • Save mikeash/1355671 to your computer and use it in GitHub Desktop.
Save mikeash/1355671 to your computer and use it in GitHub Desktop.
Multiple return
// 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;
}
@thesoftwarephilosopher
Copy link

This really is just plain crazy.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment