CollectionUtils.m
author Jens Alfke <jens@mooseyard.com>
Thu May 14 20:44:32 2009 -0700 (2009-05-14)
changeset 31 2068331949ee
parent 29 8874aff14cc9
child 33 d52f6b0d94be
permissions -rw-r--r--
* Optimized Olivier's MYDirectoryWatcher fix (by caching the watcher's standardized path)
* Added -[NSData my_UTF8ToString] to CollectionUtils.
     1 //
     2 //  CollectionUtils.m
     3 //  MYUtilities
     4 //
     5 //  Created by Jens Alfke on 1/5/08.
     6 //  Copyright 2008 Jens Alfke. All rights reserved.
     7 //
     8 
     9 #import "CollectionUtils.h"
    10 #import "Test.h"
    11 
    12 
    13 NSDictionary* _dictof(const struct _dictpair* pairs, size_t count)
    14 {
    15     CAssert(count<10000);
    16     id objects[count], keys[count];
    17     size_t n = 0;
    18     for( size_t i=0; i<count; i++,pairs++ ) {
    19         if( pairs->value ) {
    20             objects[n] = pairs->value;
    21             keys[n] = pairs->key;
    22             n++;
    23         }
    24     }
    25     return [NSDictionary dictionaryWithObjects: objects forKeys: keys count: n];
    26 }
    27 
    28 
    29 NSMutableDictionary* _mdictof(const struct _dictpair* pairs, size_t count)
    30 {
    31     CAssert(count<10000);
    32     id objects[count], keys[count];
    33     size_t n = 0;
    34     for( size_t i=0; i<count; i++,pairs++ ) {
    35         if( pairs->value ) {
    36             objects[n] = pairs->value;
    37             keys[n] = pairs->key;
    38             n++;
    39         }
    40     }
    41     return [NSMutableDictionary dictionaryWithObjects: objects forKeys: keys count: n];
    42 }
    43 
    44 
    45 NSArray* $apply( NSArray *src, SEL selector, id defaultValue )
    46 {
    47     NSMutableArray *dst = [NSMutableArray arrayWithCapacity: src.count];
    48     for( id obj in src ) {
    49         id result = [obj performSelector: selector] ?: defaultValue;
    50         [dst addObject: result];
    51     }
    52     return dst;
    53 }
    54 
    55 NSArray* $applyKeyPath( NSArray *src, NSString *keyPath, id defaultValue )
    56 {
    57     NSMutableArray *dst = [NSMutableArray arrayWithCapacity: src.count];
    58     for( id obj in src ) {
    59         id result = [obj valueForKeyPath: keyPath] ?: defaultValue;
    60         [dst addObject: result];
    61     }
    62     return dst;
    63 }
    64 
    65 
    66 BOOL $equal(id obj1, id obj2)      // Like -isEqual: but works even if either/both are nil
    67 {
    68     if( obj1 )
    69         return obj2 && [obj1 isEqual: obj2];
    70     else
    71         return obj2==nil;
    72 }
    73 
    74 
    75 NSValue* _box(const void *value, const char *encoding)
    76 {
    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
    78     char e = encoding[0];
    79     if( e=='r' )                // ignore 'const' modifier
    80         e = encoding[1];
    81     switch( e ) {
    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];
    97     }
    98 }
    99 
   100 
   101 id _cast( Class requiredClass, id object )
   102 {
   103     if( object && ! [object isKindOfClass: requiredClass] )
   104         [NSException raise: NSInvalidArgumentException format: @"%@ required, but got %@ %p",
   105          requiredClass,[object class],object];
   106     return object;
   107 }
   108 
   109 id _castNotNil( Class requiredClass, id object )
   110 {
   111     if( ! [object isKindOfClass: requiredClass] )
   112         [NSException raise: NSInvalidArgumentException format: @"%@ required, but got %@ %p",
   113          requiredClass,[object class],object];
   114     return object;
   115 }
   116 
   117 id _castIf( Class requiredClass, id object )
   118 {
   119     if( object && ! [object isKindOfClass: requiredClass] )
   120         object = nil;
   121     return object;
   122 }
   123 
   124 NSArray* _castArrayOf(Class itemClass, NSArray *a)
   125 {
   126     id item;
   127     foreach( item, $cast(NSArray,a) )
   128         _cast(itemClass,item);
   129     return a;
   130 }
   131 
   132 
   133 void setObj( id *var, id value )
   134 {
   135     if( value != *var ) {
   136         [*var release];
   137         *var = [value retain];
   138     }
   139 }
   140 
   141 BOOL ifSetObj( id *var, id value )
   142 {
   143     if( value != *var && ![value isEqual: *var] ) {
   144         [*var release];
   145         *var = [value retain];
   146         return YES;
   147     } else {
   148         return NO;
   149     }
   150 }
   151 
   152 
   153 void setString( NSString **var, NSString *value )
   154 {
   155     if( value != *var ) {
   156         [*var release];
   157         *var = [value copy];
   158     }
   159 }
   160 
   161 
   162 BOOL ifSetString( NSString **var, NSString *value )
   163 {
   164     if( value != *var && ![value isEqualToString: *var] ) {
   165         [*var release];
   166         *var = [value copy];
   167         return YES;
   168     } else {
   169         return NO;
   170     }
   171 }
   172 
   173 
   174 NSString* $string( const char *utf8Str )
   175 {
   176     if( utf8Str )
   177         return [NSString stringWithCString: utf8Str encoding: NSUTF8StringEncoding];
   178     else
   179         return nil;
   180 }
   181 
   182 
   183 BOOL kvSetSet( id owner, NSString *property, NSMutableSet *set, NSSet *newSet ) {
   184     CAssert(set);
   185     if (!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]; 
   195         return YES;
   196     } else
   197         return NO;
   198 }
   199 
   200 
   201 BOOL kvAddToSet( id owner, NSString *property, NSMutableSet *set, id objToAdd ) {
   202     CAssert(set);
   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];
   213         return YES;
   214     } else
   215         return NO;
   216 }
   217 
   218 
   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];
   230         return YES;
   231     } else
   232         return NO;
   233 }
   234 
   235 
   236 @implementation NSArray (MYUtils)
   237 
   238 - (BOOL) my_containsObjectIdenticalTo: (id)object
   239 {
   240     return [self indexOfObjectIdenticalTo: object] != NSNotFound;
   241 }
   242 
   243 @end
   244 
   245 
   246 
   247 
   248 @implementation NSSet (MYUtils)
   249 
   250 + (NSSet*) my_unionOfSet: (NSSet*)set1 andSet: (NSSet*)set2
   251 {
   252     if( set1 == set2 || set2.count==0 )
   253         return set1;
   254     else if( set1.count==0 )
   255         return set2;
   256     else {
   257         NSMutableSet *result = [set1 mutableCopy];
   258         [result unionSet: set2];
   259         return [result autorelease];
   260     }
   261 }
   262 
   263 + (NSSet*) my_intersectionOfSet: (NSSet*)set1 andSet: (NSSet*)set2
   264 {
   265     if( set1 == set2 || set1.count==0 )
   266         return set1;
   267     else if( set2.count==0 )
   268         return set2;
   269     else {
   270         NSMutableSet *result = [set1 mutableCopy];
   271         [result intersectSet: set2];
   272         return [result autorelease];
   273     }
   274 }
   275 
   276 + (NSSet*) my_differenceOfSet: (NSSet*)set1 andSet: (NSSet*)set2
   277 {
   278     if( set1.count==0 || set2.count==0 )
   279         return set1;
   280     else if( set1==set2 )
   281         return [NSSet set];
   282     else {
   283         NSMutableSet *result = [set1 mutableCopy];
   284         [result minusSet: set2];
   285         return [result autorelease];
   286     }
   287 }
   288 
   289 @end
   290 
   291 
   292 
   293 @implementation NSData (MYUtils)
   294 
   295 - (NSString*) my_UTF8ToString {
   296     return [[[NSString alloc] initWithData: self encoding: NSUTF8StringEncoding] autorelease];
   297 }
   298 
   299 @end
   300 
   301 
   302 
   303 #import "Test.h"
   304 
   305 TestCase(CollectionUtils) {
   306     NSArray *a = $array(@"foo",@"bar",@"baz");
   307     //Log(@"a = %@",a);
   308     NSArray *aa = [NSArray arrayWithObjects: @"foo",@"bar",@"baz",nil];
   309     CAssertEqual(a,aa);
   310     
   311     const char *cstr = "a C string";
   312     id o = $object(cstr);
   313     //Log(@"o = %@",o);
   314     CAssertEqual(o,@"a C string");
   315     
   316     NSDictionary *d = $dict({@"int",    $object(1)},
   317                             {@"double", $object(-1.1)},
   318                             {@"char",   $object('x')},
   319                             {@"ulong",  $object(1234567UL)},
   320                             {@"longlong",$object(987654321LL)},
   321                             {@"cstr",   $object(cstr)});
   322     //Log(@"d = %@",d);
   323     NSDictionary *dd = [NSDictionary dictionaryWithObjectsAndKeys:
   324                         [NSNumber numberWithInt: 1],                    @"int",
   325                         [NSNumber numberWithDouble: -1.1],              @"double",
   326                         [NSNumber numberWithChar: 'x'],                 @"char",
   327                         [NSNumber numberWithUnsignedLong: 1234567UL],   @"ulong",
   328                         [NSNumber numberWithDouble: 987654321LL],       @"longlong",
   329                         @"a C string",                                  @"cstr",
   330                         nil];
   331     CAssertEqual(d,dd);
   332 }
   333 
   334 
   335 /*
   336  Copyright (c) 2008, Jens Alfke <jens@mooseyard.com>. All rights reserved.
   337  
   338  Redistribution and use in source and binary forms, with or without modification, are permitted
   339  provided that the following conditions are met:
   340  
   341  * Redistributions of source code must retain the above copyright notice, this list of conditions
   342  and the following disclaimer.
   343  * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
   344  and the following disclaimer in the documentation and/or other materials provided with the
   345  distribution.
   346  
   347  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   348  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   349  FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   350  BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   351  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   352   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   353  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   354  THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   355  */