Index: src/OFDictionary.h ================================================================== --- src/OFDictionary.h +++ src/OFDictionary.h @@ -6,10 +6,12 @@ * * This file is part of libobjfw. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE included in * the packaging of this file. */ + +#include #import "OFObject.h" #import "OFList.h" /** @@ -34,10 +36,18 @@ * \param bits The size of the hash to use * \return A new autoreleased OFDictionary */ + dictionaryWithHashSize: (int)hashsize; +/** + * Creates a new OFDictionary with the specified objects. + * + * \param first The first key + * \return A new autoreleased OFDictionary + */ ++ dictionaryWithKeysAndObjects: (OFObject *)first, ...; + /** * Initializes an already allocated OFDictionary, defaulting to a 12 bit hash. * * \return An initialized OFDictionary */ @@ -49,10 +59,27 @@ * \param bits The size of the hash to use * \return An initialized OFDictionary */ - initWithHashSize: (int)hashsize; +/** + * Initialized an already allocated OFDictionary with the specified objects. + * + * \param first The first key + * \return A new initialized OFDictionary + */ +- initWithKeysAndObjects: (OFObject *)first, ...; + +/** + * Initialized an already allocated OFDictionary with the specified objects. + * + * \param first The first key + * \return A new initialized OFDictionary + */ +- initWithKey: (OFObject *)first + andArgList: (va_list)args; + /** * \return The average number of items in a used bucket. Buckets that are * completely empty are not in the calculation. If this value is >= 2.0, * you should resize the dictionary, in most cases even earlier! */ Index: src/OFDictionary.m ================================================================== --- src/OFDictionary.m +++ src/OFDictionary.m @@ -31,10 +31,23 @@ + dictionaryWithHashSize: (int)hashsize { return [[[self alloc] initWithHashSize: hashsize] autorelease]; } + ++ dictionaryWithKeysAndObjects: (OFObject *)first, ... +{ + id ret; + va_list args; + + va_start(args, first); + ret = [[[self alloc] initWithKey: first + andArgList: args] autorelease]; + va_end(args); + + return ret; +} - init { self = [super init]; @@ -81,10 +94,90 @@ size = 0; [self dealloc]; @throw e; } memset(data, 0, size * sizeof(OFList*)); + + return self; +} + +- initWithKeysAndObjects: (OFObject *)first, ... +{ + id ret; + va_list args; + + va_start(args, first); + ret = [self initWithKey: first + andArgList: args]; + va_end(args); + + return ret; +} + +- initWithKey: (OFObject *)first + andArgList: (va_list)args +{ + id key, obj; + Class c; + uint32_t hash; + + self = [self init]; + obj = va_arg(args, id); + + if (obj == nil) { + c = isa; + [self dealloc]; + @throw [OFInvalidArgumentException newWithClass: isa + andSelector: _cmd]; + } + + hash = [first hash] & (size - 1); + key = [first copy]; + + @try { + if (data[hash] == nil) + data[hash] = [[OFList alloc] init]; + + [data[hash] append: key]; + [data[hash] append: obj]; + } @catch (OFException *e) { + [self dealloc]; + @throw e; + } @finally { + [key release]; + } + + while ((key = va_arg(args, id)) != nil) { + if ((obj = va_arg(args, id)) == nil) { + c = isa; + [self dealloc]; + @throw [OFInvalidArgumentException newWithClass: isa + andSelector: _cmd]; + } + + hash = [key hash] & (size - 1); + + @try { + key = [key copy]; + } @catch (OFException *e) { + [self dealloc]; + @throw e; + } + + @try { + if (data[hash] == nil) + data[hash] = [[OFList alloc] init]; + + [data[hash] append: key]; + [data[hash] append: obj]; + } @catch (OFException *e) { + [self dealloc]; + @throw e; + } @finally { + [key release]; + } + } return self; } - (float)averageItemsPerBucket Index: tests/OFDictionary/OFDictionary.m ================================================================== --- tests/OFDictionary/OFDictionary.m +++ tests/OFDictionary/OFDictionary.m @@ -21,10 +21,11 @@ int main() { OFDictionary *dict = [OFMutableDictionary dictionaryWithHashSize: 16]; + OFDictionary *dict2; OFIterator *iter = [dict iterator]; OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; OFString *key1 = [OFString stringWithCString: "key1"]; OFString *key2 = [OFString stringWithCString: "key2"]; @@ -36,51 +37,65 @@ [dict set: key2 to: value2]; [pool release]; if (strcmp([[dict get: @"key1"] cString], "value1")) { - puts("\033[K\033[1;31mTest 1/7 failed!\033[m"); + puts("\033[K\033[1;31mTest 1/9 failed!\033[m"); return 1; } if (strcmp([[dict get: key2] cString], "value2")) { - puts("\033[K\033[1;31mTest 2/7 failed!\033[m"); + puts("\033[K\033[1;31mTest 2/9 failed!\033[m"); return 1; } if (![[iter nextObject] isEqual: @"key2"] || ![[iter nextObject] isEqual: @"value2"] || ![[iter nextObject] isEqual: @"key1"] || ![[iter nextObject] isEqual: @"value1"]) { - puts("\033[K\033[1;31mTest 3/7 failed!\033[m"); + puts("\033[K\033[1;31mTest 3/9 failed!\033[m"); return 1; } [dict changeHashSize: 8]; iter = [dict iterator]; if (![[iter nextObject] isEqual: @"key1"] || ![[iter nextObject] isEqual: @"value1"] || ![[iter nextObject] isEqual: @"key2"] || ![[iter nextObject] isEqual: @"value2"]) { - puts("\033[K\033[1;31mTest 4/7 failed!\033[m"); + puts("\033[K\033[1;31mTest 4/9 failed!\033[m"); return 1; } if ([dict averageItemsPerBucket] != 1.0) { - puts("\033[K\033[1;31mTest 5/7 failed!\033[m"); + puts("\033[K\033[1;31mTest 5/9 failed!\033[m"); return 1; } if ([iter nextObject] != nil) { - puts("\033[K\033[1;31mTest 6/7 failed!\033[m"); + puts("\033[K\033[1;31mTest 6/9 failed!\033[m"); return 1; } if ([dict get: @"key3"] != nil) { - puts("\033[K\033[1;31mTest 7/7 failed!\033[m"); + puts("\033[K\033[1;31mTest 7/9 failed!\033[m"); + return 1; + } + + dict2 = [OFDictionary dictionaryWithKeysAndObjects: @"foo", @"bar", + @"baz", @"qux", + nil]; + + if (![[dict2 get: @"foo"] isEqual: @"bar"]) { + puts("\033[K\033[1;31mTest 8/9 failed!\033[m"); + return 1; + } + + if (![[dict2 get: @"baz"] isEqual: @"qux"]) { + puts("\033[K\033[1;31mTest 9/9 failed!\033[m"); return 1; } - puts("\033[1;32mTests successful: 7/7\033[0m"); + puts("\033[1;32mTests successful: 9/9\033[0m"); return 0; }