diff options
Diffstat (limited to 'Foundation/GTMNSDictionary+CaseInsensitive.m')
-rw-r--r-- | Foundation/GTMNSDictionary+CaseInsensitive.m | 116 |
1 files changed, 116 insertions, 0 deletions
diff --git a/Foundation/GTMNSDictionary+CaseInsensitive.m b/Foundation/GTMNSDictionary+CaseInsensitive.m new file mode 100644 index 0000000..96494c2 --- /dev/null +++ b/Foundation/GTMNSDictionary+CaseInsensitive.m @@ -0,0 +1,116 @@ +// +// GTMNSDictionary+CaseInsensitive.m +// +// Copyright 2009 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. +// + +#import "GTMNSDictionary+CaseInsensitive.h" +#import "GTMDefines.h" +#import <CoreFoundation/CoreFoundation.h> + +@interface NSMutableDictionary (GTMNSMutableDictionaryCaseInsensitiveAdditions) + +// Returns a mutable equivalent to GTMNSDictionaryCaseInsensitiveAdditions. +- (id)gtm_initWithDictionaryCaseInsensitive:(NSDictionary *)dictionary; + +@end + +static Boolean CaseInsensitiveEqualCallback(const void *a, const void *b) { + id idA = (id)a; + id idB = (id)b; + Boolean ret = FALSE; + if ([idA isKindOfClass:[NSString class]] && + [idB isKindOfClass:[NSString class]]) { + ret = ([idA compare:idB options:NSCaseInsensitiveSearch|NSLiteralSearch] + == NSOrderedSame); + } else { + ret = [idA isEqual:idB]; + } + return ret; +} + +static CFHashCode CaseInsensitiveHashCallback(const void *value) { + id idValue = (id)value; + CFHashCode ret = 0; + if ([idValue isKindOfClass:[NSString class]]) { + ret = [[idValue lowercaseString] hash]; + } else { + ret = [idValue hash]; + } + return ret; +} + +@implementation NSDictionary (GTMNSDictionaryCaseInsensitiveAdditions) + +- (id)gtm_initWithDictionaryCaseInsensitive:(NSDictionary *)dictionary { + [self release]; + self = nil; + + CFIndex count = 0; + void *keys = NULL; + void *values = NULL; + + if (dictionary) { + count = CFDictionaryGetCount((CFDictionaryRef)dictionary); + + if (count) { + keys = malloc(count * sizeof(void *)); + values = malloc(count * sizeof(void *)); + if (!keys || !values) { + free(keys); + free(values); + return self; + } + + CFDictionaryGetKeysAndValues((CFDictionaryRef)dictionary, keys, values); + } + } + + CFDictionaryKeyCallBacks keyCallbacks = kCFCopyStringDictionaryKeyCallBacks; + _GTMDevAssert(keyCallbacks.version == 0, + @"CFDictionaryKeyCallBacks structure updated"); + keyCallbacks.equal = CaseInsensitiveEqualCallback; + keyCallbacks.hash = CaseInsensitiveHashCallback; + + self = (id)CFDictionaryCreate(kCFAllocatorDefault, + keys, values, count, &keyCallbacks, + &kCFTypeDictionaryValueCallBacks); + + free(keys); + free(values); + + return self; +} + ++ (id)gtm_dictionaryWithDictionaryCaseInsensitive:(NSDictionary *)dictionary { + return [[[self alloc] + gtm_initWithDictionaryCaseInsensitive:dictionary] autorelease]; +} + +@end + +@implementation NSMutableDictionary (GTMNSMutableDictionaryCaseInsensitiveAdditions) + +- (id)gtm_initWithDictionaryCaseInsensitive:(NSDictionary *)dictionary { + if ((self = [super gtm_initWithDictionaryCaseInsensitive:dictionary])) { + id copy = (id)CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, + (CFDictionaryRef)self); + [self release]; + self = copy; + } + return self; +} + +@end |