Index: src/OFDictionary.h ================================================================== --- src/OFDictionary.h +++ src/OFDictionary.h @@ -29,11 +29,11 @@ * \brief A class for storing objects in a hash table. */ @interface OFDictionary: OFObject { - struct of_dictionary_bucket *data; + struct of_dictionary_bucket **data; uint32_t size; size_t count; } /** @@ -160,18 +160,18 @@ @end /// \cond internal @interface OFDictionaryEnumerator: OFEnumerator { - struct of_dictionary_bucket *data; + struct of_dictionary_bucket **data; uint32_t size; unsigned long mutations; unsigned long *mutations_ptr; uint32_t pos; } -- initWithData: (struct of_dictionary_bucket*)data +- initWithData: (struct of_dictionary_bucket**)data size: (uint32_t)size mutationsPointer: (unsigned long*)mutations_ptr; @end @interface OFDictionaryObjectEnumerator: OFDictionaryEnumerator @@ -181,6 +181,6 @@ @end /// \endcond #import "OFMutableDictionary.h" -extern const int of_dictionary_deleted_bucket; +extern struct of_dictionary_bucket of_dictionary_deleted_bucket; Index: src/OFDictionary.m ================================================================== --- src/OFDictionary.m +++ src/OFDictionary.m @@ -18,14 +18,14 @@ #import "OFArray.h" #import "OFAutoreleasePool.h" #import "OFExceptions.h" #import "macros.h" -const int of_dictionary_deleted_bucket = 0; +struct of_dictionary_bucket of_dictionary_deleted_bucket = {}; -#define BUCKET_SIZE sizeof(struct of_dictionary_bucket) -#define DELETED (id)&of_dictionary_deleted_bucket +#define BUCKET struct of_dictionary_bucket +#define DELETED &of_dictionary_deleted_bucket @implementation OFDictionary + dictionary; { return [[[self alloc] init] autorelease]; @@ -68,21 +68,21 @@ self = [super init]; size = 1; @try { - data = [self allocMemoryWithSize: BUCKET_SIZE]; + data = [self allocMemoryWithSize: sizeof(BUCKET*)]; } @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; + data[0] = NULL; return self; } - initWithDictionary: (OFDictionary*)dict @@ -99,11 +99,14 @@ selector: _cmd]; } @try { data = [self allocMemoryForNItems: dict->size - withSize: BUCKET_SIZE]; + withSize: sizeof(BUCKET*)]; + + for (i = 0; i < dict->size; i++) + data[i] = NULL; } @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. @@ -115,64 +118,69 @@ size = dict->size; count = dict->count; for (i = 0; i < size; i++) { OFObject *key; + BUCKET *b; - if (dict->data[i].key == nil || dict->data[i].key == DELETED) { - data[i].key = nil; + if (dict->data[i] == NULL || dict->data[i] == DELETED) continue; - } @try { - key = [dict->data[i].key copy]; + b = [self allocMemoryWithSize: sizeof(BUCKET)]; + key = [dict->data[i]->key copy]; } @catch (OFException *e) { [self dealloc]; @throw e; } @try { - [dict->data[i].object retain]; + [dict->data[i]->object retain]; } @catch (OFException *e) { [key release]; [self dealloc]; @throw e; } - data[i].key = key; - data[i].object = dict->data[i].object; - data[i].hash = dict->data[i].hash; + b->key = key; + b->object = dict->data[i]->object; + b->hash = dict->data[i]->hash; + data[i] = b; } return self; } - initWithObject: (OFObject*)obj forKey: (OFObject *)key { uint32_t i; + BUCKET *b; self = [self init]; @try { data = [self allocMemoryForNItems: 2 - withSize: BUCKET_SIZE]; + withSize: sizeof(BUCKET*)]; + + size = 2; + for (i = 0; i < size; i++) + data[i] = NULL; } @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; } - memset(data, 0, 2 * BUCKET_SIZE); - size = 2; i = [key hash] & 1; @try { + b = [self allocMemoryWithSize: sizeof(BUCKET)]; key = [key copy]; } @catch (OFException *e) { [self dealloc]; @throw e; } @@ -183,13 +191,14 @@ [key release]; [self dealloc]; @throw e; } - data[i].key = key; - data[i].object = obj; - data[i].hash = [key hash]; + b->key = key; + b->object = obj; + b->hash = [key hash]; + data[i] = b; count = 1; return self; } @@ -200,10 +209,12 @@ size_t i; self = [super init]; @try { + uint32_t j; + keys_carray = [keys cArray]; objs_carray = [objs cArray]; count = [keys count]; if (count > UINT32_MAX) @@ -213,63 +224,69 @@ if (size == 0) @throw [OFOutOfRangeException newWithClass: isa]; data = [self allocMemoryForNItems: size - withSize: BUCKET_SIZE]; + withSize: sizeof(BUCKET*)]; + + for (j = 0; j < size; j++) + data[j] = NULL; } @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; } - memset(data, 0, size * BUCKET_SIZE); for (i = 0; i < count; i++) { uint32_t j, hash, last; hash = [keys_carray[i] hash]; last = size; - for (j = hash & (size - 1); j < last && data[j].key != nil && - ![data[j].key isEqual: keys_carray[i]]; j++); + for (j = hash & (size - 1); j < last && data[j] != NULL; j++) + if ([data[j]->key isEqual: keys_carray[i]]) + break; /* In case the last bucket is already used */ if (j >= last) { last = hash & (size - 1); - for (j = 0; j < last && data[j].key != nil && - ![data[j].key isEqual: keys_carray[i]]; j++); + for (j = 0; j < last && data[j] != NULL; j++) + if ([data[j]->key isEqual: keys_carray[i]]) + break; } /* Key not in dictionary */ - if (j >= last || ![data[j].key isEqual: keys_carray[i]]) { + if (j >= last || data[j] == NULL || + ![data[j]->key isEqual: keys_carray[i]]) { + BUCKET *b; OFObject *key; last = size; j = hash & (size - 1); - for (; j < last && data[j].key != nil; j++); + for (; j < last && data[j] != NULL; j++); /* In case the last bucket is already used */ if (j >= last) { last = hash & (size - 1); - for (j = 0; j < last && data[j].key != nil; - j++); + for (j = 0; j < last && data[j] != NULL; j++); } if (j >= last) { Class c = isa; [self dealloc]; @throw [OFOutOfRangeException newWithClass: c]; } @try { + b = [self allocMemoryWithSize: sizeof(BUCKET)]; key = [keys_carray[i] copy]; } @catch (OFException *e) { [self dealloc]; @throw e; } @@ -280,13 +297,14 @@ [key release]; [self dealloc]; @throw e; } - data[j].key = key; - data[j].object = objs_carray[i]; - data[j].hash = hash; + b->key = key; + b->object = objs_carray[i]; + b->hash = hash; + data[j] = b; continue; } /* @@ -300,18 +318,18 @@ [self dealloc]; @throw e; } @try { - [data[j].object release]; + [data[j]->object release]; } @catch (OFException *e) { [objs_carray[i] release]; [self dealloc]; @throw e; } - data[j].object = objs_carray[i]; + data[j]->object = objs_carray[i]; } return self; } @@ -329,10 +347,11 @@ } - initWithKey: (OFObject *)key argList: (va_list)args { + BUCKET *b; OFObject *obj; size_t i; uint32_t j, hash; va_list args2; @@ -356,24 +375,31 @@ @throw [OFOutOfRangeException newWithClass: c]; } @try { data = [self allocMemoryForNItems: size - withSize: BUCKET_SIZE]; + withSize: sizeof(BUCKET*)]; + + for (j = 0; j < size; j++) + data[j] = NULL; } @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; } - memset(data, 0, size * BUCKET_SIZE); - if (key == nil) - return self; + if (key == nil) { + Class c = isa; + size = 0; + [self dealloc]; + @throw [OFInvalidArgumentException newWithClass: c + selector: _cmd]; + } if ((obj = va_arg(args, OFObject*)) == nil) { Class c = isa; [self dealloc]; @throw [OFInvalidArgumentException newWithClass: c @@ -383,10 +409,11 @@ /* Add first key / object pair */ hash = [key hash]; j = hash & (size - 1); @try { + b = [self allocMemoryWithSize: sizeof(BUCKET)]; key = [key copy]; } @catch (OFException *e) { [self dealloc]; @throw e; } @@ -397,13 +424,14 @@ [key release]; [self dealloc]; @throw e; } - data[j].key = key; - data[j].object = obj; - data[j].hash = hash; + b->key = key; + b->object = obj; + b->hash = hash; + data[j] = b; for (i = 1; i < count; i++) { uint32_t last; key = va_arg(args, OFObject *); @@ -417,43 +445,46 @@ } hash = [key hash]; last = size; - for (j = hash & (size - 1); j < last && data[j].key != nil && - ![data[j].key isEqual: key]; j++); + for (j = hash & (size - 1); j < last && data[j] != NULL; j++) + if ([data[j]->key isEqual: key]) + break; /* In case the last bucket is already used */ if (j >= last) { last = hash & (size - 1); - for (j = 0; j < last && data[j].key != nil && - ![data[j].key isEqual: key]; j++); + for (j = 0; j < last && data[j] != NULL; j++) + if ([data[j]->key isEqual: key]) + break; } /* Key not in dictionary */ - if (j >= last || ![data[j].key isEqual: key]) { + if (j >= last || data[j] == NULL || + ![data[j]->key isEqual: key]) { last = size; j = hash & (size - 1); - for (; j < last && data[j].key != nil; j++); + for (; j < last && data[j] != NULL; j++); /* In case the last bucket is already used */ if (j >= last) { last = hash & (size - 1); - for (j = 0; j < last && data[j].key != nil; - j++); + for (j = 0; j < last && data[j] != NULL; j++); } if (j >= last) { Class c = isa; [self dealloc]; @throw [OFOutOfRangeException newWithClass: c]; } @try { + b = [self allocMemoryWithSize: sizeof(BUCKET)]; key = [key copy]; } @catch (OFException *e) { [self dealloc]; @throw e; } @@ -464,13 +495,14 @@ [key release]; [self dealloc]; @throw e; } - data[j].key = key; - data[j].object = obj; - data[j].hash = hash; + b->key = key; + b->object = obj; + b->hash = hash; + data[j] = b; continue; } /* @@ -484,18 +516,18 @@ [self dealloc]; @throw e; } @try { - [data[j].object release]; + [data[j]->object release]; } @catch (OFException *e) { [obj release]; [self dealloc]; @throw e; } - data[j].object = obj; + data[j]->object = obj; } return self; } @@ -508,30 +540,30 @@ selector: _cmd]; hash = [key hash]; last = size; - for (i = hash & (size - 1); i < last && data[i].key != nil; i++) { - if (data[i].key == DELETED) + for (i = hash & (size - 1); i < last && data[i] != NULL; i++) { + if (data[i] == DELETED) continue; - if ([data[i].key isEqual: key]) - return [[data[i].object retain] autorelease]; + if ([data[i]->key isEqual: key]) + return [[data[i]->object retain] autorelease]; } if (i < last) return nil; /* In case the last bucket is already used */ last = hash & (size - 1); - for (i = 0; i < last && data[i].key != nil; i++) { - if (data[i].key == DELETED) + for (i = 0; i < last && data[i] != NULL; i++) { + if (data[i] == DELETED) continue; - if ([data[i].key isEqual: key]) - return [[data[i].object retain] autorelease]; + if ([data[i]->key isEqual: key]) + return [[data[i]->object retain] autorelease]; } return nil; } @@ -556,12 +588,13 @@ if ([dict count] != count) return NO; for (i = 0; i < size; i++) - if (data[i].key != nil && data[i].key != DELETED && - ![[dict objectForKey: data[i].key] isEqual: data[i].object]) + if (data[i] != NULL && data[i]!= DELETED && + ![[dict objectForKey: data[i]->key] + isEqual: data[i]->object]) return NO; return YES; } @@ -570,15 +603,15 @@ count: (int)count_ { int i; for (i = 0; i < count_; i++) { - for (; state->state < size && (data[state->state].key == nil || - data[state->state].key == DELETED); state->state++); + for (; state->state < size && (data[state->state] == NULL || + data[state->state] == DELETED); state->state++); if (state->state < size) { - objects[i] = data[state->state].key; + objects[i] = data[state->state]->key; state->state++; } else break; } @@ -607,13 +640,13 @@ - (void)dealloc { uint32_t i; for (i = 0; i < size; i++) { - if (data[i].key != nil && data[i].key != DELETED) { - [data[i].key release]; - [data[i].object release]; + if (data[i] != NULL && data[i] != DELETED) { + [data[i]->key release]; + [data[i]->object release]; } } [super dealloc]; } @@ -624,22 +657,22 @@ uint32_t hash; OF_HASH_INIT(hash); for (i = 0; i < size; i++) { - if (data[i].key != nil && data[i].key != DELETED) { - uint32_t kh = [data[i].key hash]; - - OF_HASH_ADD(hash, kh >> 24); - OF_HASH_ADD(hash, (kh >> 16) & 0xFF); - OF_HASH_ADD(hash, (kh >> 8) & 0xFF); - OF_HASH_ADD(hash, kh & 0xFF); - - OF_HASH_ADD(hash, data[i].hash >> 24); - OF_HASH_ADD(hash, (data[i].hash >> 16) & 0xFF); - OF_HASH_ADD(hash, (data[i].hash >> 8) & 0xFF); - OF_HASH_ADD(hash, data[i].hash & 0xFF); + if (data[i] != NULL && data[i] != DELETED) { + uint32_t h = [data[i]->object hash]; + + OF_HASH_ADD(hash, data[i]->hash >> 24); + OF_HASH_ADD(hash, (data[i]->hash >> 16) & 0xFF); + OF_HASH_ADD(hash, (data[i]->hash >> 8) & 0xFF); + OF_HASH_ADD(hash, data[i]->hash & 0xFF); + + OF_HASH_ADD(hash, h >> 24); + OF_HASH_ADD(hash, (h >> 16) & 0xFF); + OF_HASH_ADD(hash, (h >> 8) & 0xFF); + OF_HASH_ADD(hash, h & 0xFF); } } OF_HASH_FINALIZE(hash); @@ -647,11 +680,11 @@ } @end /// \cond internal @implementation OFDictionaryEnumerator -- initWithData: (struct of_dictionary_bucket*)data_ +- initWithData: (struct of_dictionary_bucket**)data_ size: (uint32_t)size_ mutationsPointer: (unsigned long*)mutations_ptr_ { self = [super init]; @@ -678,15 +711,15 @@ - (id)nextObject { if (mutations_ptr != NULL && *mutations_ptr != mutations) @throw [OFEnumerationMutationException newWithClass: isa]; - for (; pos < size && (data[pos].key == nil || - data[pos].key == DELETED); pos++); + for (; pos < size && (data[pos] == NULL || + data[pos] == DELETED); pos++); if (pos < size) - return data[pos++].object; + return data[pos++]->object; else return nil; } @end @@ -694,15 +727,15 @@ - (id)nextObject { if (mutations_ptr != NULL && *mutations_ptr != mutations) @throw [OFEnumerationMutationException newWithClass: isa]; - for (; pos < size && (data[pos].key == nil || - data[pos].key == DELETED); pos++); + for (; pos < size && (data[pos] == NULL || + data[pos] == DELETED); pos++); if (pos < size) - return data[pos++].key; + return data[pos++]->key; else return nil; } @end /// \endcond Index: src/OFMutableDictionary.m ================================================================== --- src/OFMutableDictionary.m +++ src/OFMutableDictionary.m @@ -15,19 +15,19 @@ #import "OFMutableDictionary.h" #import "OFExceptions.h" #import "macros.h" -#define BUCKET_SIZE sizeof(struct of_dictionary_bucket) -#define DELETED (id)&of_dictionary_deleted_bucket +#define BUCKET struct of_dictionary_bucket +#define DELETED &of_dictionary_deleted_bucket @implementation OFMutableDictionary - (void)_resizeForCount: (size_t)newcount { size_t fill = newcount * 4 / size; size_t newsize; - struct of_dictionary_bucket *newdata; + struct of_dictionary_bucket **newdata; uint32_t i; if (newcount > UINT32_MAX) @throw [OFOutOfRangeException newWithClass: isa]; @@ -40,39 +40,39 @@ if (newsize == 0) @throw [OFOutOfRangeException newWithClass: isa]; newdata = [self allocMemoryForNItems: newsize - withSize: BUCKET_SIZE]; - memset(newdata, 0, newsize * BUCKET_SIZE); + withSize: sizeof(BUCKET*)]; + + for (i = 0; i < newsize; i++) + newdata[i] = NULL; for (i = 0; i < size; i++) { - if (data[i].key != nil && data[i].key != DELETED) { + if (data[i] != NULL && data[i] != DELETED) { uint32_t j, last; last = newsize; - j = data[i].hash & (newsize - 1); - for (; j < last && newdata[j].key != nil; j++); + j = data[i]->hash & (newsize - 1); + for (; j < last && newdata[j] != NULL; j++); /* In case the last bucket is already used */ if (j >= last) { - last = data[i].hash & (newsize - 1); + last = data[i]->hash & (newsize - 1); for (j = 0; j < last && - newdata[j].key != nil; i++); + newdata[j] != NULL; i++); } if (j >= last) { [self freeMemory: newdata]; @throw [OFOutOfRangeException - newWithClass: [self class]]; + newWithClass: isa]; } - newdata[j].key = data[i].key; - newdata[j].object = data[i].object; - newdata[j].hash = data[i].hash; + newdata[j] = data[i]; } } [self freeMemory: data]; data = newdata; @@ -89,72 +89,83 @@ selector: _cmd]; hash = [key hash]; last = size; - for (i = hash & (size - 1); i < last && data[i].key != nil; i++) { - if (data[i].key == DELETED) + for (i = hash & (size - 1); i < last && data[i] != NULL; i++) { + if (data[i] == DELETED) continue; - if ([data[i].key isEqual: key]) + if ([data[i]->key isEqual: key]) break; } /* In case the last bucket is already used */ if (i >= last) { last = hash & (size - 1); - for (i = 0; i < last && data[i].key != nil; i++) { - if (data[i].key == DELETED) + for (i = 0; i < last && data[i] != NULL; i++) { + if (data[i] == DELETED) continue; - if ([data[i].key isEqual: key]) + if ([data[i]->key isEqual: key]) break; } } /* Key not in dictionary */ - if (i >= last || data[i].key == nil || data[i].key == DELETED || - ![data[i].key isEqual: key]) { + if (i >= last || data[i] == NULL || data[i] == DELETED || + ![data[i]->key isEqual: key]) { + BUCKET *b; + [self _resizeForCount: count + 1]; mutations++; last = size; - for (i = hash & (size - 1); i < last && data[i].key != nil && - data[i].key != DELETED; i++); + for (i = hash & (size - 1); i < last && data[i] != NULL && + data[i] != DELETED; i++); /* In case the last bucket is already used */ if (i >= last) { last = hash & (size - 1); - for (i = 0; i < last && data[i].key != nil && - data[i].key != DELETED; i++); + for (i = 0; i < last && data[i] != NULL && + data[i] != DELETED; i++); } if (i >= last) @throw [OFOutOfRangeException newWithClass: isa]; - key = [key copy]; + b = [self allocMemoryWithSize: sizeof(BUCKET)]; + + @try { + key = [key copy]; + } @catch (OFException *e) { + [self freeMemory: b]; + } + @try { [obj retain]; } @catch (OFException *e) { + [self freeMemory: b]; [key release]; @throw e; } - data[i].key = key; - data[i].object = obj; - data[i].hash = hash; + b->key = key; + b->object = obj; + b->hash = hash; + data[i] = b; count++; return self; } [obj retain]; - [data[i].object release]; - data[i].object = obj; + [data[i]->object release]; + data[i]->object = obj; return self; } - removeObjectForKey: (OFObject*)key @@ -166,18 +177,19 @@ selector: _cmd]; hash = [key hash]; last = size; - for (i = hash & (size - 1); i < last && data[i].key != nil; i++) { - if (data[i].key == DELETED) + for (i = hash & (size - 1); i < last && data[i] != NULL; i++) { + if (data[i] == DELETED) continue; - if ([data[i].key isEqual: key]) { - [data[i].key release]; - [data[i].object release]; - data[i].key = DELETED; + if ([data[i]->key isEqual: key]) { + [data[i]->key release]; + [data[i]->object release]; + [self freeMemory: data[i]]; + data[i] = DELETED; count--; mutations++; [self _resizeForCount: count]; @@ -189,18 +201,19 @@ return self; /* In case the last bucket is already used */ last = hash & (size - 1); - for (i = 0; i < last && data[i].key != nil; i++) { - if (data[i].key == DELETED) + for (i = 0; i < last && data[i] != NULL; i++) { + if (data[i] == DELETED) continue; - if ([data[i].key isEqual: key]) { - [data[i].key release]; - [data[i].object release]; - data[i].key = DELETED; + if ([data[i]->key isEqual: key]) { + [data[i]->key release]; + [data[i]->object release]; + [self freeMemory: data[i]]; + data[i] = DELETED; count--; mutations++; [self _resizeForCount: count]; @@ -221,15 +234,15 @@ count: (int)count_ { int i; for (i = 0; i < count_; i++) { - for (; state->state < size && (data[state->state].key == nil || - data[state->state].key == DELETED); state->state++); + for (; state->state < size && (data[state->state] == NULL || + data[state->state] == DELETED); state->state++); if (state->state < size) { - objects[i] = data[state->state].key; + objects[i] = data[state->state]->key; state->state++; } else break; }