Index: src/OFArray.m ================================================================== --- src/OFArray.m +++ src/OFArray.m @@ -180,12 +180,11 @@ va_end(arguments); return ret; } -- (instancetype)initWithObject: (id)firstObject - arguments: (va_list)arguments +- (instancetype)initWithObject: (id)firstObject arguments: (va_list)arguments { size_t count = 1; va_list argumentsCopy; id *objects; Index: src/OFDictionary.h ================================================================== --- src/OFDictionary.h +++ src/OFDictionary.h @@ -147,10 +147,17 @@ * @return A new autoreleased OFDictionary */ + (instancetype)dictionaryWithKeysAndObjects: (KeyType)firstKey, ... OF_SENTINEL; +/** + * @brief Initializes an already allocated OFDictionary to be empty. + * + * @return An initialized OFDictionary + */ +- (instancetype)init OF_DESIGNATED_INITIALIZER; + /** * @brief Initializes an already allocated OFDictionary with the specified * OFDictionary. * * @param dictionary An OFDictionary @@ -189,11 +196,11 @@ * @param count The number of objects in the arrays * @return An initialized OFDictionary */ - (instancetype)initWithObjects: (ObjectType const _Nonnull *_Nonnull)objects forKeys: (KeyType const _Nonnull *_Nonnull)keys - count: (size_t)count; + count: (size_t)count OF_DESIGNATED_INITIALIZER; /** * @brief Initializes an already allocated OFDictionary with the specified keys * and objects. * Index: src/OFDictionary.m ================================================================== --- src/OFDictionary.m +++ src/OFDictionary.m @@ -51,10 +51,16 @@ - (instancetype)initWithDictionary: (OFDictionary *)dictionary; @end @implementation OFPlaceholderDictionary +#ifdef __clang__ +/* We intentionally don't call into super, so silence the warning. */ +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wunknown-pragmas" +# pragma clang diagnostic ignored "-Wobjc-designated-initializers" +#endif - (instancetype)init { return (id)[[OFConcreteDictionary alloc] init]; } @@ -102,10 +108,13 @@ arguments: (va_list)arguments { return (id)[[OFConcreteDictionary alloc] initWithKey: firstKey arguments: arguments]; } +#ifdef __clang__ +# pragma clang diagnostic pop +#endif OF_SINGLETON_METHODS @end @implementation OFDictionary @@ -186,23 +195,55 @@ return [super init]; } - (instancetype)initWithDictionary: (OFDictionary *)dictionary { - OF_INVALID_INIT_METHOD + void *pool = objc_autoreleasePoolPush(); + id const *objects, *keys; + size_t count; + + @try { + OFArray *objects_ = [dictionary.objectEnumerator allObjects]; + OFArray *keys_ = [dictionary.keyEnumerator allObjects]; + + count = dictionary.count; + + if (count != keys_.count || count != objects_.count) + @throw [OFInvalidArgumentException exception]; + + objects = objects_.objects; + keys = keys_.objects; + } @catch (id e) { + [self release]; + @throw e; + } + + @try { + return [self initWithObjects: objects + forKeys: keys + count: count]; + } @finally { + objc_autoreleasePoolPop(pool); + } } - (instancetype)initWithObject: (id)object forKey: (id)key { - if (key == nil || object == nil) - @throw [OFInvalidArgumentException exception]; + @try { + if (key == nil || object == nil) + @throw [OFInvalidArgumentException exception]; + } @catch (id e) { + [self release]; + @throw e; + } - return [self initWithKeysAndObjects: key, object, nil]; + return [self initWithObjects: &object forKeys: &key count: 1]; } - (instancetype)initWithObjects: (OFArray *)objects_ forKeys: (OFArray *)keys_ { + void *pool = objc_autoreleasePoolPush(); id const *objects, *keys; size_t count; @try { count = objects_.count; @@ -215,19 +256,34 @@ } @catch (id e) { [self release]; @throw e; } - return [self initWithObjects: objects forKeys: keys count: count]; + @try { + return [self initWithObjects: objects + forKeys: keys + count: count]; + } @finally { + objc_autoreleasePoolPop(pool); + } } +#ifdef __clang__ +/* We intentionally don't call into super, so silence the warning. */ +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wunknown-pragmas" +# pragma clang diagnostic ignored "-Wobjc-designated-initializers" +#endif - (instancetype)initWithObjects: (id const *)objects forKeys: (id const *)keys count: (size_t)count { OF_INVALID_INIT_METHOD } +#ifdef __clang__ +# pragma clang diagnostic pop +#endif - (instancetype)initWithKeysAndObjects: (id)firstKey, ... { id ret; va_list arguments; @@ -239,11 +295,55 @@ return ret; } - (instancetype)initWithKey: (id)firstKey arguments: (va_list)arguments { - OF_INVALID_INIT_METHOD + size_t count = 1; + id *objects = NULL, *keys = NULL; + va_list argumentsCopy; + + va_copy(argumentsCopy, arguments); + while (va_arg(argumentsCopy, id) != nil) + count++; + + @try { + size_t i = 0; + id key, object; + + if (firstKey == nil || count % 2 != 0) + @throw [OFInvalidArgumentException exception]; + + count /= 2; + + objects = OFAllocMemory(count, sizeof(id)); + keys = OFAllocMemory(count, sizeof(id)); + + while ((key = va_arg(arguments, id)) != nil && + (object = va_arg(arguments, id)) != nil) { + OFEnsure(i < count); + + objects[i] = object; + keys[i] = key; + + i++; + } + } @catch (id e) { + OFFreeMemory(objects); + OFFreeMemory(keys); + + [self release]; + @throw e; + } + + @try { + return [self initWithObjects: objects + forKeys: keys + count: count]; + } @finally { + OFFreeMemory(objects); + OFFreeMemory(keys); + } } - (id)objectForKey: (id)key { OF_UNRECOGNIZED_SELECTOR Index: src/OFMutableDictionary.h ================================================================== --- src/OFMutableDictionary.h +++ src/OFMutableDictionary.h @@ -52,18 +52,25 @@ * @param capacity The initial capacity for the OFMutableDictionary * @return A new autoreleased OFMutableDictionary */ + (instancetype)dictionaryWithCapacity: (size_t)capacity; +/** + * @brief Initializes an already allocated OFMutableDictionary to be empty. + * + * @return An initialized OFMutableDictionary + */ +- (instancetype)init OF_DESIGNATED_INITIALIZER; + /** * @brief Initializes an already allocated OFMutableDictionary with enough * memory to hold the specified number of objects. * * @param capacity The initial capacity for the OFMutableDictionary * @return An initialized OFMutableDictionary */ -- (instancetype)initWithCapacity: (size_t)capacity; +- (instancetype)initWithCapacity: (size_t)capacity OF_DESIGNATED_INITIALIZER; /** * @brief Sets an object for a key. * * A key can be any object that conforms to the OFCopying protocol. Index: src/OFMutableDictionary.m ================================================================== --- src/OFMutableDictionary.m +++ src/OFMutableDictionary.m @@ -107,15 +107,36 @@ + (instancetype)dictionaryWithCapacity: (size_t)capacity { return [[[self alloc] initWithCapacity: capacity] autorelease]; } + +- (instancetype)init +{ + return [super init]; +} + +#ifdef __clang__ +/* We intentionally don't call into super, so silence the warning. */ +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wunknown-pragmas" +# pragma clang diagnostic ignored "-Wobjc-designated-initializers" +#endif +- (instancetype)initWithObjects: (id const *)objects + forKeys: (id const *)keys + count: (size_t)count +{ + OF_INVALID_INIT_METHOD +} - (instancetype)initWithCapacity: (size_t)capacity { OF_INVALID_INIT_METHOD } +#ifdef __clang__ +# pragma clang diagnostic pop +#endif - (void)setObject: (id)object forKey: (id)key { OF_UNRECOGNIZED_SELECTOR }