TwitterImagePipeline/Project/NSDictionary+TIPAdditions.m (109 lines of code) (raw):

// // NSDictionary+TIPAdditions.m // TwitterImagePipeline // // Created on 9/9/16. // Copyright © 2020 Twitter. All rights reserved. // #import "NSDictionary+TIPAdditions.h" #import "TIP_Project.h" NS_ASSUME_NONNULL_BEGIN @implementation NSDictionary (TIPAdditions) - (nullable NSSet *)tip_keysMatchingCaseInsensitiveKey:(NSString *)key { NSMutableSet *keys = nil; TIPAssert([key isKindOfClass:[NSString class]]); if ([key isKindOfClass:[NSString class]]) { for (NSString *otherKey in self.allKeys) { TIPAssert([otherKey isKindOfClass:[NSString class]]); if ([otherKey caseInsensitiveCompare:key] == NSOrderedSame) { // TWITTER_STYLE_CASE_INSENSITIVE_COMPARE_NIL_PRECHECKED if (!keys) { keys = [NSMutableSet set]; } [keys addObject:otherKey]; } } } return keys; } - (nullable NSArray *)tip_objectsForCaseInsensitiveKey:(NSString *)key { TIPAssert(key); NSSet *keys = [self tip_keysMatchingCaseInsensitiveKey:key]; NSMutableArray *objects = (keys.count > 0) ? [NSMutableArray array] : nil; for (NSString *otherKey in keys) { [objects addObject:self[otherKey]]; } return objects; } - (nullable id)tip_objectForCaseInsensitiveKey:(NSString *)key { id value = [self objectForKey:key]; if (!value) { for (NSString *innerKey in self.allKeys) { if ([innerKey isKindOfClass:[NSString class]]) { if ([innerKey caseInsensitiveCompare:key] == NSOrderedSame) { // TWITTER_STYLE_CASE_INSENSITIVE_COMPARE_NIL_PRECHECKED value = [self objectForKey:innerKey]; break; } } } } return value; } - (id)tip_copyWithLowercaseKeys { return [self tip_copyToMutable:NO uppercase:NO]; } - (id)tip_copyWithUppercaseKeys { return [self tip_copyToMutable:NO uppercase:YES]; } - (id)tip_mutableCopyWithLowercaseKeys { return [self tip_copyToMutable:YES uppercase:NO]; } - (id)tip_mutableCopyWithUppercaseKeys { return [self tip_copyToMutable:YES uppercase:YES]; } - (id)tip_copyToMutable:(BOOL)mutable uppercase:(BOOL)uppercase { NSMutableDictionary *replacementDict = nil; for (NSString *key in self) { NSString *updatedKey = uppercase ? [key uppercaseString] : [key lowercaseString]; if (![key isEqualToString:updatedKey]) { if (!replacementDict) { replacementDict = [self mutableCopy]; } [replacementDict removeObjectForKey:key]; replacementDict[updatedKey] = self[key]; } } return replacementDict ?: (mutable ? [self mutableCopy] : [self copy]); } @end @implementation NSMutableDictionary (TIPAdditions) - (void)tip_removeObjectsForCaseInsensitiveKey:(NSString *)key { TIPAssert(key); NSArray *keys = [[self tip_keysMatchingCaseInsensitiveKey:key] allObjects]; if (keys) { [self removeObjectsForKeys:keys]; } } - (void)tip_setObject:(id)object forCaseInsensitiveKey:(NSString *)key { TIPAssert(key); [self tip_removeObjectsForCaseInsensitiveKey:key]; #ifndef __clang_analyzer__ // reports key can be nil nil; we prefer to crash if it is self[key] = object; #endif } - (void)tip_makeAllKeysLowercase { NSDictionary *d = [self tip_mutableCopyWithLowercaseKeys]; [self removeAllObjects]; [self addEntriesFromDictionary:d]; } - (void)tip_makeAllKeysUppercase { NSDictionary *d = [self tip_mutableCopyWithUppercaseKeys]; [self removeAllObjects]; [self addEntriesFromDictionary:d]; } @end NS_ASSUME_NONNULL_END