-
Notifications
You must be signed in to change notification settings - Fork 19
/
Copy pathMACollectionUtilities.h
119 lines (94 loc) · 4.17 KB
/
MACollectionUtilities.h
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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
//
// MACollectionUtilities.h
// MACollectionUtilities
//
// Created by Michael Ash on 10/11/10.
// Copyright 2010 Michael Ash. All rights reserved.
//
#import <Foundation/Foundation.h>
// make sure non-Clang compilers can still compile
#ifndef __has_feature
#define __has_feature(x) 0
#endif
// no ARC ? -> declare the ARC attributes we use to be a no-op, so the compiler won't whine
#if ! __has_feature( objc_arc )
#define __autoreleasing
#define __bridge
#endif
#define ARRAY(...) ([NSArray arrayWithObjects: IDARRAY(__VA_ARGS__) count: IDCOUNT(__VA_ARGS__)])
#define SET(...) ([NSSet setWithObjects: IDARRAY(__VA_ARGS__) count: IDCOUNT(__VA_ARGS__)])
// this is key/object order, not object/key order, thus all the fuss
#define DICT(...) MADictionaryWithKeysAndObjects(IDARRAY(__VA_ARGS__), IDCOUNT(__VA_ARGS__) / 2)
#define MAP(collection, ...) EACH_WRAPPER([collection ma_map: ^id (id obj) { return (__VA_ARGS__); }])
#define SELECT(collection, ...) EACH_WRAPPER([collection ma_select: ^BOOL (id obj) { return (__VA_ARGS__) != 0; }])
#define REJECT(collection, ...) EACH_WRAPPER([collection ma_select: ^BOOL (id obj) { return (__VA_ARGS__) == 0; }])
#define MATCH(collection, ...) EACH_WRAPPER([collection ma_match: ^BOOL (id obj) { return (__VA_ARGS__) != 0; }])
#define REDUCE(collection, initial, ...) EACH_WRAPPER([collection ma_reduce: (initial) block: ^id (id a, id b) { return (__VA_ARGS__); }])
#define DO(collection, ...) EACH_WRAPPER_NORETURN([collection ma_do: ^void (id obj) { __VA_ARGS__;}])
#define EACH(array) MAEachHelper(array, &MA_eachTable)
#define SORTED(collection, ...) [collection ma_sorted: ^BOOL (id a, id b) { return (__VA_ARGS__) != 0; }]
@interface NSArray (MACollectionUtilities)
- (NSArray *)ma_map: (id (^)(id obj))block;
- (NSArray *)ma_select: (BOOL (^)(id obj))block;
- (id)ma_match: (BOOL (^)(id obj))block;
- (id)ma_reduce: (id)initial block: (id (^)(id a, id b))block;
- (void)ma_do: (void (^)(id obj))block;
- (NSArray *)ma_sorted: (BOOL (^)(id a, id b))lessThan;
@end
@interface NSSet (MACollectionUtilities)
- (NSSet *)ma_map: (id (^)(id obj))block;
- (NSSet *)ma_select: (BOOL (^)(id obj))block;
- (id)ma_match: (BOOL (^)(id obj))block;
- (void)ma_do: (void (^)(id obj))block;
- (NSArray *)ma_sorted: (BOOL (^)(id a, id b))lessThan;
@end
// ===========================================================================
// internal utility whatnot that needs to be externally visible for the macros
#define IDARRAY(...) ((__autoreleasing id[]){ __VA_ARGS__ })
#define IDCOUNT(...) (sizeof(IDARRAY(__VA_ARGS__)) / sizeof(id))
#define EACH_WRAPPER(...) (^{ __block CFMutableDictionaryRef MA_eachTable = nil; \
(void)MA_eachTable; \
__typeof__(__VA_ARGS__) MA_retval = __VA_ARGS__; \
if(MA_eachTable) \
CFRelease(MA_eachTable); \
return MA_retval; \
}())
#define EACH_WRAPPER_NORETURN(...) (^{ __block CFMutableDictionaryRef MA_eachTable = nil; \
(void)MA_eachTable; \
__VA_ARGS__; \
if(MA_eachTable) \
CFRelease(MA_eachTable); \
}())
static inline NSDictionary *MADictionaryWithKeysAndObjects(id *keysAndObjs, NSUInteger count)
{
id keys[count];
id objs[count];
for(NSUInteger i = 0; i < count; i++)
{
keys[i] = keysAndObjs[i * 2];
objs[i] = keysAndObjs[i * 2 + 1];
}
return [NSDictionary dictionaryWithObjects: objs forKeys: keys count: count];
}
static inline id MAEachHelper(NSArray *array, CFMutableDictionaryRef *eachTablePtr)
{
if(!*eachTablePtr)
{
CFDictionaryKeyCallBacks keycb = {
0,
kCFTypeDictionaryKeyCallBacks.retain,
kCFTypeDictionaryKeyCallBacks.release,
kCFTypeDictionaryKeyCallBacks.copyDescription,
NULL,
NULL
};
*eachTablePtr = CFDictionaryCreateMutable(NULL, 0, &keycb, &kCFTypeDictionaryValueCallBacks);
}
NSEnumerator *enumerator = (__bridge id)CFDictionaryGetValue(*eachTablePtr, (__bridge CFArrayRef)array);
if(!enumerator)
{
enumerator = [array objectEnumerator];
CFDictionarySetValue(*eachTablePtr, (__bridge CFArrayRef)array, (__bridge void *)enumerator);
}
return [enumerator nextObject];
}