* Added kv*Set utility functions for handling KV grunge when mutating an NSSet property.
* Change CFMakeCollectable to NSMakeCollectable.
5 // Created by Jens Alfke on 1/5/08.
6 // Copyright 2008 Jens Alfke. All rights reserved.
9 #import "CollectionUtils.h"
13 NSDictionary* _dictof(const struct _dictpair* pairs, size_t count)
16 id objects[count], keys[count];
18 for( size_t i=0; i<count; i++,pairs++ ) {
20 objects[n] = pairs->value;
25 return [NSDictionary dictionaryWithObjects: objects forKeys: keys count: n];
29 NSMutableDictionary* _mdictof(const struct _dictpair* pairs, size_t count)
32 id objects[count], keys[count];
34 for( size_t i=0; i<count; i++,pairs++ ) {
36 objects[n] = pairs->value;
41 return [NSMutableDictionary dictionaryWithObjects: objects forKeys: keys count: n];
45 NSArray* $apply( NSArray *src, SEL selector, id defaultValue )
47 NSMutableArray *dst = [NSMutableArray arrayWithCapacity: src.count];
48 for( id obj in src ) {
49 id result = [obj performSelector: selector] ?: defaultValue;
50 [dst addObject: result];
55 NSArray* $applyKeyPath( NSArray *src, NSString *keyPath, id defaultValue )
57 NSMutableArray *dst = [NSMutableArray arrayWithCapacity: src.count];
58 for( id obj in src ) {
59 id result = [obj valueForKeyPath: keyPath] ?: defaultValue;
60 [dst addObject: result];
66 BOOL $equal(id obj1, id obj2) // Like -isEqual: but works even if either/both are nil
69 return obj2 && [obj1 isEqual: obj2];
75 NSValue* _box(const void *value, const char *encoding)
77 // file:///Developer/Documentation/DocSets/com.apple.ADC_Reference_Library.DeveloperTools.docset/Contents/Resources/Documents/documentation/DeveloperTools/gcc-4.0.1/gcc/Type-encoding.html
79 if( e=='r' ) // ignore 'const' modifier
82 case 'c': return [NSNumber numberWithChar: *(char*)value];
83 case 'C': return [NSNumber numberWithUnsignedChar: *(char*)value];
84 case 's': return [NSNumber numberWithShort: *(short*)value];
85 case 'S': return [NSNumber numberWithUnsignedShort: *(unsigned short*)value];
86 case 'i': return [NSNumber numberWithInt: *(int*)value];
87 case 'I': return [NSNumber numberWithUnsignedInt: *(unsigned int*)value];
88 case 'l': return [NSNumber numberWithLong: *(long*)value];
89 case 'L': return [NSNumber numberWithUnsignedLong: *(unsigned long*)value];
90 case 'q': return [NSNumber numberWithLongLong: *(long long*)value];
91 case 'Q': return [NSNumber numberWithUnsignedLongLong: *(unsigned long long*)value];
92 case 'f': return [NSNumber numberWithFloat: *(float*)value];
93 case 'd': return [NSNumber numberWithDouble: *(double*)value];
94 case '*': return [NSString stringWithUTF8String: *(char**)value];
95 case '@': return *(id*)value;
96 default: return [NSValue value: value withObjCType: encoding];
101 id _cast( Class requiredClass, id object )
103 if( object && ! [object isKindOfClass: requiredClass] )
104 [NSException raise: NSInvalidArgumentException format: @"%@ required, but got %@ %p",
105 requiredClass,[object class],object];
109 id _castNotNil( Class requiredClass, id object )
111 if( ! [object isKindOfClass: requiredClass] )
112 [NSException raise: NSInvalidArgumentException format: @"%@ required, but got %@ %p",
113 requiredClass,[object class],object];
117 id _castIf( Class requiredClass, id object )
119 if( object && ! [object isKindOfClass: requiredClass] )
124 NSArray* _castArrayOf(Class itemClass, NSArray *a)
127 foreach( item, $cast(NSArray,a) )
128 _cast(itemClass,item);
133 void setObj( id *var, id value )
135 if( value != *var ) {
137 *var = [value retain];
141 BOOL ifSetObj( id *var, id value )
143 if( value != *var && ![value isEqual: *var] ) {
145 *var = [value retain];
153 void setString( NSString **var, NSString *value )
155 if( value != *var ) {
162 BOOL ifSetString( NSString **var, NSString *value )
164 if( value != *var && ![value isEqualToString: *var] ) {
174 NSString* $string( const char *utf8Str )
177 return [NSString stringWithCString: utf8Str encoding: NSUTF8StringEncoding];
183 BOOL kvSetSet( id owner, NSString *property, NSMutableSet *set, NSSet *newSet ) {
186 newSet = [NSSet set];
187 if (![set isEqualToSet: newSet]) {
188 [owner willChangeValueForKey: property
189 withSetMutation:NSKeyValueSetSetMutation
190 usingObjects:newSet];
191 [set setSet: newSet];
192 [owner didChangeValueForKey: property
193 withSetMutation:NSKeyValueSetSetMutation
194 usingObjects:newSet];
201 BOOL kvAddToSet( id owner, NSString *property, NSMutableSet *set, id objToAdd ) {
203 if (![set containsObject: objToAdd]) {
204 NSSet *changedObjects = [[NSSet alloc] initWithObjects: &objToAdd count: 1];
205 [owner willChangeValueForKey: property
206 withSetMutation: NSKeyValueUnionSetMutation
207 usingObjects: changedObjects];
208 [set addObject: objToAdd];
209 [owner didChangeValueForKey: property
210 withSetMutation: NSKeyValueUnionSetMutation
211 usingObjects: changedObjects];
212 [changedObjects release];
219 BOOL kvRemoveFromSet( id owner, NSString *property, NSMutableSet *set, id objToRemove ) {
220 if ([set containsObject: objToRemove]) {
221 NSSet *changedObjects = [[NSSet alloc] initWithObjects: &objToRemove count: 1];
222 [owner willChangeValueForKey: property
223 withSetMutation: NSKeyValueMinusSetMutation
224 usingObjects: changedObjects];
225 [set removeObject: objToRemove];
226 [owner didChangeValueForKey: property
227 withSetMutation: NSKeyValueMinusSetMutation
228 usingObjects: changedObjects];
229 [changedObjects release];
236 @implementation NSArray (MYUtils)
238 - (BOOL) my_containsObjectIdenticalTo: (id)object
240 return [self indexOfObjectIdenticalTo: object] != NSNotFound;
248 @implementation NSSet (MYUtils)
250 + (NSSet*) my_unionOfSet: (NSSet*)set1 andSet: (NSSet*)set2
252 if( set1 == set2 || set2.count==0 )
254 else if( set1.count==0 )
257 NSMutableSet *result = [set1 mutableCopy];
258 [result unionSet: set2];
259 return [result autorelease];
263 + (NSSet*) my_intersectionOfSet: (NSSet*)set1 andSet: (NSSet*)set2
265 if( set1 == set2 || set1.count==0 )
267 else if( set2.count==0 )
270 NSMutableSet *result = [set1 mutableCopy];
271 [result intersectSet: set2];
272 return [result autorelease];
276 + (NSSet*) my_differenceOfSet: (NSSet*)set1 andSet: (NSSet*)set2
278 if( set1.count==0 || set2.count==0 )
280 else if( set1==set2 )
283 NSMutableSet *result = [set1 mutableCopy];
284 [result minusSet: set2];
285 return [result autorelease];
295 TestCase(CollectionUtils) {
296 NSArray *a = $array(@"foo",@"bar",@"baz");
298 NSArray *aa = [NSArray arrayWithObjects: @"foo",@"bar",@"baz",nil];
301 const char *cstr = "a C string";
302 id o = $object(cstr);
304 CAssertEqual(o,@"a C string");
306 NSDictionary *d = $dict({@"int", $object(1)},
307 {@"double", $object(-1.1)},
308 {@"char", $object('x')},
309 {@"ulong", $object(1234567UL)},
310 {@"longlong",$object(987654321LL)},
311 {@"cstr", $object(cstr)});
313 NSDictionary *dd = [NSDictionary dictionaryWithObjectsAndKeys:
314 [NSNumber numberWithInt: 1], @"int",
315 [NSNumber numberWithDouble: -1.1], @"double",
316 [NSNumber numberWithChar: 'x'], @"char",
317 [NSNumber numberWithUnsignedLong: 1234567UL], @"ulong",
318 [NSNumber numberWithDouble: 987654321LL], @"longlong",
319 @"a C string", @"cstr",
326 Copyright (c) 2008, Jens Alfke <jens@mooseyard.com>. All rights reserved.
328 Redistribution and use in source and binary forms, with or without modification, are permitted
329 provided that the following conditions are met:
331 * Redistributions of source code must retain the above copyright notice, this list of conditions
332 and the following disclaimer.
333 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
334 and the following disclaimer in the documentation and/or other materials provided with the
337 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
338 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
339 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
340 BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
341 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
342 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
343 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
344 THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.