Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
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;
}
@sdegutis
Copy link

sdegutis commented Jun 20, 2014

This really is just plain crazy.

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