CollectionUtils.m
author Jens Alfke <jens@mooseyard.com>
Mon Aug 10 08:29:32 2009 -0700 (2009-08-10)
changeset 34 50c4f26bcc1b
parent 31 2068331949ee
permissions -rw-r--r--
Fixed signed/unsigned warnings in Base64.m.
     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 void setObjCopy( id *var, id valueToCopy ) {
   153     if( valueToCopy != *var ) {
   154         [*var release];
   155         *var = [valueToCopy copy];
   156     }
   157 }
   158 
   159 BOOL ifSetObjCopy( id *var, id value )
   160 {
   161     if( value != *var && ![value isEqual: *var] ) {
   162         [*var release];
   163         *var = [value copy];
   164         return YES;
   165     } else {
   166         return NO;
   167     }
   168 }
   169 
   170 
   171 NSString* $string( const char *utf8Str )
   172 {
   173     if( utf8Str )
   174         return [NSString stringWithCString: utf8Str encoding: NSUTF8StringEncoding];
   175     else
   176         return nil;
   177 }
   178 
   179 
   180 BOOL kvSetSet( id owner, NSString *property, NSMutableSet *set, NSSet *newSet ) {
   181     CAssert(set);
   182     if (!newSet)
   183         newSet = [NSSet set];
   184     if (![set isEqualToSet: newSet]) {
   185         [owner willChangeValueForKey: property
   186                      withSetMutation:NSKeyValueSetSetMutation 
   187                         usingObjects:newSet]; 
   188         [set setSet: newSet];
   189         [owner didChangeValueForKey: property 
   190                     withSetMutation:NSKeyValueSetSetMutation 
   191                        usingObjects:newSet]; 
   192         return YES;
   193     } else
   194         return NO;
   195 }
   196 
   197 
   198 BOOL kvAddToSet( id owner, NSString *property, NSMutableSet *set, id objToAdd ) {
   199     CAssert(set);
   200     if (![set containsObject: objToAdd]) {
   201         NSSet *changedObjects = [[NSSet alloc] initWithObjects: &objToAdd count: 1];
   202         [owner willChangeValueForKey: property
   203                      withSetMutation: NSKeyValueUnionSetMutation 
   204                         usingObjects: changedObjects]; 
   205         [set addObject: objToAdd];
   206         [owner didChangeValueForKey: property 
   207                     withSetMutation: NSKeyValueUnionSetMutation 
   208                        usingObjects: changedObjects]; 
   209         [changedObjects release];
   210         return YES;
   211     } else
   212         return NO;
   213 }
   214 
   215 
   216 BOOL kvRemoveFromSet( id owner, NSString *property, NSMutableSet *set, id objToRemove ) {
   217     if ([set containsObject: objToRemove]) {
   218         NSSet *changedObjects = [[NSSet alloc] initWithObjects: &objToRemove count: 1];
   219         [owner willChangeValueForKey: property
   220                      withSetMutation: NSKeyValueMinusSetMutation 
   221                         usingObjects: changedObjects]; 
   222         [set removeObject: objToRemove];
   223         [owner didChangeValueForKey: property 
   224                     withSetMutation: NSKeyValueMinusSetMutation 
   225                        usingObjects: changedObjects]; 
   226         [changedObjects release];
   227         return YES;
   228     } else
   229         return NO;
   230 }
   231 
   232 
   233 @implementation NSArray (MYUtils)
   234 
   235 - (BOOL) my_containsObjectIdenticalTo: (id)object
   236 {
   237     return [self indexOfObjectIdenticalTo: object] != NSNotFound;
   238 }
   239 
   240 @end
   241 
   242 
   243 
   244 
   245 @implementation NSSet (MYUtils)
   246 
   247 + (NSSet*) my_unionOfSet: (NSSet*)set1 andSet: (NSSet*)set2
   248 {
   249     if( set1 == set2 || set2.count==0 )
   250         return set1;
   251     else if( set1.count==0 )
   252         return set2;
   253     else {
   254         NSMutableSet *result = [set1 mutableCopy];
   255         [result unionSet: set2];
   256         return [result autorelease];
   257     }
   258 }
   259 
   260 + (NSSet*) my_intersectionOfSet: (NSSet*)set1 andSet: (NSSet*)set2
   261 {
   262     if( set1 == set2 || set1.count==0 )
   263         return set1;
   264     else if( set2.count==0 )
   265         return set2;
   266     else {
   267         NSMutableSet *result = [set1 mutableCopy];
   268         [result intersectSet: set2];
   269         return [result autorelease];
   270     }
   271 }
   272 
   273 + (NSSet*) my_differenceOfSet: (NSSet*)set1 andSet: (NSSet*)set2
   274 {
   275     if( set1.count==0 || set2.count==0 )
   276         return set1;
   277     else if( set1==set2 )
   278         return [NSSet set];
   279     else {
   280         NSMutableSet *result = [set1 mutableCopy];
   281         [result minusSet: set2];
   282         return [result autorelease];
   283     }
   284 }
   285 
   286 @end
   287 
   288 
   289 
   290 @implementation NSData (MYUtils)
   291 
   292 - (NSString*) my_UTF8ToString {
   293     return [[[NSString alloc] initWithData: self encoding: NSUTF8StringEncoding] autorelease];
   294 }
   295 
   296 @end
   297 
   298 
   299 
   300 #import "Test.h"
   301 
   302 TestCase(CollectionUtils) {
   303     NSArray *a = $array(@"foo",@"bar",@"baz");
   304     //Log(@"a = %@",a);
   305     NSArray *aa = [NSArray arrayWithObjects: @"foo",@"bar",@"baz",nil];
   306     CAssertEqual(a,aa);
   307     
   308     const char *cstr = "a C string";
   309     id o = $object(cstr);
   310     //Log(@"o = %@",o);
   311     CAssertEqual(o,@"a C string");
   312     
   313     NSDictionary *d = $dict({@"int",    $object(1)},
   314                             {@"double", $object(-1.1)},
   315                             {@"char",   $object('x')},
   316                             {@"ulong",  $object(1234567UL)},
   317                             {@"longlong",$object(987654321LL)},
   318                             {@"cstr",   $object(cstr)});
   319     //Log(@"d = %@",d);
   320     NSDictionary *dd = [NSDictionary dictionaryWithObjectsAndKeys:
   321                         [NSNumber numberWithInt: 1],                    @"int",
   322                         [NSNumber numberWithDouble: -1.1],              @"double",
   323                         [NSNumber numberWithChar: 'x'],                 @"char",
   324                         [NSNumber numberWithUnsignedLong: 1234567UL],   @"ulong",
   325                         [NSNumber numberWithDouble: 987654321LL],       @"longlong",
   326                         @"a C string",                                  @"cstr",
   327                         nil];
   328     CAssertEqual(d,dd);
   329 }
   330 
   331 
   332 /*
   333  Copyright (c) 2008, Jens Alfke <jens@mooseyard.com>. All rights reserved.
   334  
   335  Redistribution and use in source and binary forms, with or without modification, are permitted
   336  provided that the following conditions are met:
   337  
   338  * Redistributions of source code must retain the above copyright notice, this list of conditions
   339  and the following disclaimer.
   340  * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
   341  and the following disclaimer in the documentation and/or other materials provided with the
   342  distribution.
   343  
   344  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   345  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   346  FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   347  BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   348  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   349   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   350  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   351  THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   352  */