Artifact 3ddd956ea435e735fa64ded6c57296b234e0bb393419f2d7e081b8afa79b7ae3:
- File
src/OFDictionary.m
— part of check-in
[bbf1f79b8f]
at
2009-09-08 16:06:10
on branch trunk
— New OFDictionary implementation and removal of a hack in OFList.
The new implementation is easier to use as it does automatic resizing,
but therefore it's not realtime-capable anymore. The new implementation
should also be a little bit faster.I decided to change the implementation as only very few need a
realtime-capable dictionary and those few will most likely write their
own implementation for their specific case anyway.As the new implementation no longer uses OFList, this also made it
possible to remove a hack from OFList. (user: js, size: 5389) [annotate] [blame] [check-ins using]
/* * Copyright (c) 2008 - 2009 * Jonathan Schleifer <js@webkeks.org> * * All rights reserved. * * 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 "config.h" #include <string.h> #import "OFDictionary.h" #import "OFIterator.h" #import "OFAutoreleasePool.h" #import "OFExceptions.h" #define BUCKET_SIZE sizeof(struct of_dictionary_bucket) /* References for static linking */ void _references_to_categories_of_OFDictionary() { _OFIterator_reference = 1; } @implementation OFDictionary + dictionary; { return [[[self alloc] init] autorelease]; } + dictionaryWithDictionary: (OFDictionary*)dict { return [[[self alloc] initWithDictionary: dict] autorelease]; } + dictionaryWithObject: (OFObject*)obj forKey: (OFObject <OFCopying>*)key { return [[[self alloc] initWithObject: obj forKey: key] autorelease]; } + dictionaryWithObjects: (OFArray*)objs forKeys: (OFArray*)keys { return [[[self alloc] initWithObjects: objs forKeys: keys] autorelease]; } + dictionaryWithKeysAndObjects: (OFObject <OFCopying>*)first, ... { id ret; va_list args; va_start(args, first); ret = [[[self alloc] initWithKey: first argList: args] autorelease]; va_end(args); return ret; } - init { self = [super init]; size = 1; @try { data = [self allocMemoryWithSize: BUCKET_SIZE]; } @catch (OFException *e) { /* * We can't use [super dealloc] on OS X here. Compiler bug? * Anyway, set size to 0 so that [self dealloc] works. */ size = 0; [self dealloc]; @throw e; } data[0].key = nil; return self; } - initWithDictionary: (OFDictionary*)dict { size_t i; self = [super init]; if (dict == nil) { Class c = isa; size = 0; [self dealloc]; @throw [OFInvalidArgumentException newWithClass: c selector: _cmd]; } @try { data = [self allocMemoryForNItems: dict->size withSize: BUCKET_SIZE]; } @catch (OFException *e) { /* * We can't use [super dealloc] on OS X here. Compiler bug? * Anyway, we didn't do anything yet anyway, so [self dealloc] * works. */ [self dealloc]; @throw e; } size = dict->size; for (i = 0; i < size; i++) { if (dict->data[i].key != nil) { data[i].key = [dict->data[i].key copy]; data[i].object = [dict->data[i].object retain]; data[i].hash = dict->data[i].hash; } else data[i].key = nil; } return self; } - initWithObject: (OFObject*)obj forKey: (OFObject <OFCopying>*)key { const SEL sel = @selector(setObject:forKey:); IMP set = [OFMutableDictionary instanceMethodForSelector: sel]; self = [self init]; @try { set(self, sel, obj, key); } @catch (OFException *e) { [self dealloc]; @throw e; } return self; } - initWithObjects: (OFArray*)objs forKeys: (OFArray*)keys { id *objs_data, *keys_data; size_t objs_count, i; const SEL sel = @selector(setObject:forKey:); IMP set = [OFMutableDictionary instanceMethodForSelector: sel]; self = [self init]; objs_data = [objs data]; keys_data = [keys data]; objs_count = [objs count]; if (objs == nil || keys == nil || objs_count != [keys count]) { Class c = isa; [self dealloc]; @throw [OFInvalidArgumentException newWithClass: c selector: _cmd]; } @try { for (i = 0; i < objs_count; i++) set(self, sel, objs_data[i], keys_data[i]); } @catch (OFException *e) { [self dealloc]; @throw e; } return self; } - initWithKeysAndObjects: (OFObject <OFCopying>*)first, ... { id ret; va_list args; va_start(args, first); ret = [self initWithKey: first argList: args]; va_end(args); return ret; } - initWithKey: (OFObject <OFCopying>*)key argList: (va_list)args { const SEL sel = @selector(setObject:forKey:); IMP set = [OFMutableDictionary instanceMethodForSelector: sel]; self = [self init]; @try { set(self, sel, va_arg(args, OFObject*), key); while ((key = va_arg(args, OFObject <OFCopying>*)) != nil) set(self, sel, va_arg(args, OFObject*), key); } @catch (OFException *e) { [self dealloc]; @throw e; } return self; } - (id)objectForKey: (OFObject <OFCopying>*)key { uint32_t i, hash; if (key == nil) @throw [OFInvalidArgumentException newWithClass: isa selector: _cmd]; hash = [key hash]; for (i = hash & (size - 1); i < size && data[i].key != nil && ![data[i].key isEqual: key]; i++); /* In case the last bucket is already used */ if (i >= size) for (i = 0; i < size && data[i].key != nil && ![data[i].key isEqual: key]; i++); /* Key not in dictionary */ if (i >= size || data[i].key == nil) return nil; return data[i].object; } - (size_t)count { return count; } - (id)copy { return [self retain]; } - (id)mutableCopy { return [[OFMutableDictionary alloc] initWithDictionary: self]; } /* FIXME: Implement this! - (BOOL)isEqual { } */ - (void)dealloc { size_t i; for (i = 0; i < size; i++) { if (data[i].key != nil) { [data[i].key release]; [data[i].object release]; } } [super dealloc]; } - setObject: (OFObject*)obj forKey: (OFObject <OFCopying>*)key { @throw [OFNotImplementedException newWithClass: isa selector: _cmd]; } - removeObjectForKey: (OFObject*)key { @throw [OFNotImplementedException newWithClass: isa selector: _cmd]; } @end