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