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