Index: src/OFCountedSet_hashtable.h
==================================================================
--- src/OFCountedSet_hashtable.h
+++ src/OFCountedSet_hashtable.h
@@ -14,12 +14,12 @@
* file.
*/
#import "OFCountedSet.h"
-@class OFMutableDictionary_hashtable;
+@class OFMapTable;
@interface OFCountedSet_hashtable: OFCountedSet
{
- OFMutableDictionary_hashtable *dictionary;
+ OFMapTable *mapTable;
}
@end
Index: src/OFCountedSet_hashtable.m
==================================================================
--- src/OFCountedSet_hashtable.m
+++ src/OFCountedSet_hashtable.m
@@ -14,23 +14,22 @@
* file.
*/
#include "config.h"
-#define OF_COUNTED_SET_HASHTABLE_M
-
#import "OFMutableSet_hashtable.h"
#import "OFCountedSet_hashtable.h"
-#import "OFMutableDictionary_hashtable.h"
+#import "OFMapTable.h"
#import "OFString.h"
-#import "OFNumber.h"
#import "OFArray.h"
#import "OFXMLElement.h"
#import "OFXMLAttribute.h"
#import "OFInvalidArgumentException.h"
#import "OFInvalidFormatException.h"
+#import "OFEnumerationMutationException.h"
+#import "OFOutOfRangeException.h"
#import "autorelease.h"
@implementation OFCountedSet_hashtable
+ (void)initialize
@@ -154,27 +153,25 @@
enumerator = [objects objectEnumerator];
while ((objectElement = [enumerator nextObject]) != nil) {
void *pool2 = objc_autoreleasePoolPush();
OFXMLElement *object;
- OFXMLAttribute *count;
- OFNumber *number;
+ OFXMLAttribute *count_;
+ size_t count;
object = [[objectElement elementsForNamespace:
OF_SERIALIZATION_NS] firstObject];
- count = [objectElement attributeForName: @"count"];
+ count_ = [objectElement attributeForName: @"count"];
- if (object == nil || count == nil)
+ if (object == nil || count_ == nil)
@throw [OFInvalidFormatException
exceptionWithClass: [self class]];
- number = [OFNumber numberWithSize:
- (size_t)[[count stringValue] decimalValue]];
+ count = (size_t)[[count_ stringValue] decimalValue];
- [dictionary OF_setObject: number
- forKey: [object objectByDeserializing]
- copyKey: NO];
+ [mapTable setValue: (void*)(uintptr_t)count
+ forKey: [object objectByDeserializing]];
objc_autoreleasePoolPop(pool2);
}
objc_autoreleasePoolPop(pool);
@@ -186,61 +183,56 @@
return self;
}
- (size_t)countForObject: (id)object
{
- return [[dictionary objectForKey: object] sizeValue];
+ return (size_t)(uintptr_t)[mapTable valueForKey: object];
}
#ifdef OF_HAVE_BLOCKS
- (void)enumerateObjectsAndCountUsingBlock:
(of_counted_set_enumeration_block_t)block
{
- [dictionary enumerateKeysAndObjectsUsingBlock: ^ (id key, id object,
- BOOL *stop) {
- block(key, [object sizeValue], stop);
- }];
+ @try {
+ [mapTable enumerateKeysAndValuesUsingBlock:
+ ^ (void *key, void *value, BOOL *stop) {
+ block(key, (size_t)(uintptr_t)value, stop);
+ }];
+ } @catch (OFEnumerationMutationException *e) {
+ @throw [OFEnumerationMutationException
+ exceptionWithClass: [self class]
+ object: self];
+ }
}
#endif
- (void)addObject: (id)object
{
- void *pool = objc_autoreleasePoolPush();
- OFNumber *count;
-
- count = [[dictionary objectForKey: object] numberByIncreasing];
-
- if (count == nil)
- count = [OFNumber numberWithSize: 1];
-
- [dictionary OF_setObject: count
- forKey: object
- copyKey: NO];
-
- objc_autoreleasePoolPop(pool);
+ size_t count = (size_t)(uintptr_t)[mapTable valueForKey: object];
+
+ if (SIZE_MAX - count < 1)
+ @throw [OFOutOfRangeException exceptionWithClass: [self class]];
+
+ [mapTable setValue: (void*)(uintptr_t)(count + 1)
+ forKey: object];
}
- (void)removeObject: (id)object
{
- OFNumber *count = [dictionary objectForKey: object];
- void *pool;
+ size_t count = (size_t)(uintptr_t)[mapTable valueForKey: object];
- if (count == nil)
+ if (count == 0)
return;
- pool = objc_autoreleasePoolPush();
- count = [count numberByDecreasing];
-
- if ([count sizeValue] > 0)
- [dictionary OF_setObject: count
- forKey: object
- copyKey: NO];
- else
- [dictionary removeObjectForKey: object];
-
- objc_autoreleasePoolPop(pool);
+ count--;
+
+ if (count > 0)
+ [mapTable setValue: (void*)(uintptr_t)count
+ forKey: object];
+ else
+ [mapTable removeValueForKey: object];
}
- (void)makeImmutable
{
}
@end
Index: src/OFMapTable.h
==================================================================
--- src/OFMapTable.h
+++ src/OFMapTable.h
@@ -235,5 +235,15 @@
* @brief Resets the enumerator, so the next call to nextKey returns the first
* key again.
*/
- (void)reset;
@end
+
+@interface OFMapTableEnumeratorWrapper: OFEnumerator
+{
+ OFMapTableEnumerator *enumerator;
+ id object;
+}
+
+- initWithEnumerator: (OFMapTableEnumerator*)enumerator
+ object: (id)object;
+@end
Index: src/OFMapTable.m
==================================================================
--- src/OFMapTable.m
+++ src/OFMapTable.m
@@ -703,7 +703,54 @@
if (position < capacity)
return buckets[position++]->value;
else
return NULL;
+}
+@end
+
+@implementation OFMapTableEnumeratorWrapper
+- initWithEnumerator: (OFMapTableEnumerator*)enumerator_
+ object: (id)object_
+{
+ self = [super init];
+
+ enumerator = [enumerator_ retain];
+ object = [object_ retain];
+
+ return self;
+}
+
+- (void)dealloc
+{
+ [enumerator release];
+ [object release];
+
+ [super dealloc];
+}
+
+- (id)nextObject
+{
+ id ret;
+
+ @try {
+ ret = [enumerator nextValue];
+ } @catch (OFEnumerationMutationException *e) {
+ @throw [OFEnumerationMutationException
+ exceptionWithClass: [object class]
+ object: object];
+ }
+
+ return ret;
+}
+
+- (void)reset
+{
+ @try {
+ [enumerator reset];
+ } @catch (OFEnumerationMutationException *e) {
+ @throw [OFEnumerationMutationException
+ exceptionWithClass: [object class]
+ object: object];
+ }
}
@end
Index: src/OFMutableSet_hashtable.h
==================================================================
--- src/OFMutableSet_hashtable.h
+++ src/OFMutableSet_hashtable.h
@@ -14,12 +14,12 @@
* file.
*/
#import "OFMutableSet.h"
-@class OFMutableDictionary_hashtable;
+@class OFMapTable;
@interface OFMutableSet_hashtable: OFMutableSet
{
- OFMutableDictionary_hashtable *dictionary;
+ OFMapTable *mapTable;
}
@end
Index: src/OFMutableSet_hashtable.m
==================================================================
--- src/OFMutableSet_hashtable.m
+++ src/OFMutableSet_hashtable.m
@@ -14,16 +14,13 @@
* file.
*/
#include "config.h"
-#define OF_MUTABLE_SET_HASHTABLE_M
-
#import "OFSet_hashtable.h"
#import "OFMutableSet_hashtable.h"
-#import "OFMutableDictionary_hashtable.h"
-#import "OFNumber.h"
+#import "OFMapTable.h"
@implementation OFMutableSet_hashtable
+ (void)initialize
{
if (self == [OFMutableSet_hashtable class])
@@ -30,20 +27,19 @@
[self inheritMethodsFromClass: [OFSet_hashtable class]];
}
- (void)addObject: (id)object
{
- [dictionary OF_setObject: [OFNumber numberWithSize: 1]
- forKey: object
- copyKey: NO];
+ [mapTable setValue: (void*)1
+ forKey: object];
}
- (void)removeObject: (id)object
{
- [dictionary removeObjectForKey: object];
+ [mapTable removeValueForKey: object];
}
- (void)makeImmutable
{
object_setClass(self, [OFSet_hashtable class]);
}
@end
Index: src/OFSet_hashtable.h
==================================================================
--- src/OFSet_hashtable.h
+++ src/OFSet_hashtable.h
@@ -14,12 +14,12 @@
* file.
*/
#import "OFSet.h"
-@class OFMutableDictionary_hashtable;
+@class OFMapTable;
@interface OFSet_hashtable: OFSet
{
- OFMutableDictionary_hashtable *dictionary;
+ OFMapTable *mapTable;
}
@end
Index: src/OFSet_hashtable.m
==================================================================
--- src/OFSet_hashtable.m
+++ src/OFSet_hashtable.m
@@ -14,32 +14,70 @@
* file.
*/
#include "config.h"
-#define OF_SET_HASHTABLE_M
-
#import "OFSet_hashtable.h"
#import "OFMutableSet_hashtable.h"
#import "OFCountedSet_hashtable.h"
-#import "OFMutableDictionary_hashtable.h"
+#import "OFMapTable.h"
#import "OFArray.h"
#import "OFString.h"
-#import "OFNumber.h"
#import "OFXMLElement.h"
#import "OFInvalidArgumentException.h"
+#import "OFEnumerationMutationException.h"
#import "autorelease.h"
+static void*
+retain(void *value)
+{
+ return [(id)value retain];
+}
+
+static void
+release(void *value)
+{
+ [(id)value release];
+}
+
+static uint32_t
+hash(void *value)
+{
+ return [(id)value hash];
+}
+
+static BOOL
+equal(void *value1, void *value2)
+{
+ return [(id)value1 isEqual: (id)value2];
+}
+
+static of_map_table_functions_t keyFunctions = {
+ .retain = retain,
+ .release = release,
+ .hash = hash,
+ .equal = equal
+};
+static of_map_table_functions_t valueFunctions = {};
+
@implementation OFSet_hashtable
- init
{
+ return [self initWithCapacity: 0];
+}
+
+- initWithCapacity: (size_t)capacity
+{
self = [super init];
@try {
- dictionary = [[OFMutableDictionary_hashtable alloc] init];
+ mapTable = [[OFMapTable alloc]
+ initWithKeyFunctions: keyFunctions
+ valueFunctions: valueFunctions
+ capacity: capacity];
} @catch (id e) {
[self release];
@throw e;
}
@@ -46,32 +84,33 @@
return self;
}
- initWithSet: (OFSet*)set
{
- self = [self init];
+ size_t count;
if (set == nil)
- return self;
+ return [self init];
+
+ @try {
+ count = [set count];
+ } @catch (id e) {
+ [self release];
+ @throw e;
+ }
+
+ self = [self initWithCapacity: count];
@try {
void *pool = objc_autoreleasePoolPush();
- OFNumber *one;
OFEnumerator *enumerator;
id object;
- one = [OFNumber numberWithSize: 1];
-
- /*
- * We can't just copy the dictionary as the specified set might
- * be a counted set, but we're just a normal set.
- */
enumerator = [set objectEnumerator];
while ((object = [enumerator nextObject]) != nil)
- [dictionary OF_setObject: one
- forKey: object
- copyKey: NO];
+ [mapTable setValue: (void*)1
+ forKey: object];
objc_autoreleasePoolPop(pool);
} @catch (id e) {
[self release];
@throw e;
@@ -80,26 +119,33 @@
return self;
}
- initWithArray: (OFArray*)array
{
- self = [self init];
+ size_t count;
if (array == nil)
return self;
+ @try {
+ count = [array count];
+ } @catch (id e) {
+ [self release];
+ @throw e;
+ }
+
+ self = [self initWithCapacity: count];
+
@try {
void *pool = objc_autoreleasePoolPush();
- OFNumber *one = [OFNumber numberWithSize: 1];
OFEnumerator *enumerator;
id object;
enumerator = [array objectEnumerator];
while ((object = [enumerator nextObject]) != nil)
- [dictionary OF_setObject: one
- forKey: object
- copyKey: NO];
+ [mapTable setValue: (void*)1
+ forKey: object];
objc_autoreleasePoolPop(pool);
} @catch (id e) {
[self release];
@throw e;
@@ -109,23 +155,18 @@
}
- initWithObjects: (id const*)objects
count: (size_t)count
{
- self = [self init];
+ self = [self initWithCapacity: count];
@try {
- void *pool = objc_autoreleasePoolPush();
- OFNumber *one = [OFNumber numberWithSize: 1];
size_t i;
for (i = 0; i < count; i++)
- [dictionary OF_setObject: one
- forKey: objects[i]
- copyKey: NO];
-
- objc_autoreleasePoolPop(pool);
+ [mapTable setValue: (void*)1
+ forKey: objects[i]];
} @catch (id e) {
[self release];
@throw e;
}
@@ -133,27 +174,32 @@
}
- initWithObject: (id)firstObject
arguments: (va_list)arguments
{
- self = [self init];
+ self = [super init];
@try {
- void *pool = objc_autoreleasePoolPush();
- OFNumber *one = [OFNumber numberWithSize: 1];
id object;
+ va_list argumentsCopy;
+ size_t count;
+
+ va_copy(argumentsCopy, arguments);
+
+ for (count = 1; va_arg(argumentsCopy, id) != nil; count++);
+
+ mapTable = [[OFMapTable alloc]
+ initWithKeyFunctions: keyFunctions
+ valueFunctions: valueFunctions
+ capacity: count];
- [dictionary OF_setObject: one
- forKey: firstObject
- copyKey: NO];
+ [mapTable setValue: (void*)1
+ forKey: firstObject];
while ((object = va_arg(arguments, id)) != nil)
- [dictionary OF_setObject: one
- forKey: object
- copyKey: NO];
-
- objc_autoreleasePoolPop(pool);
+ [mapTable setValue: (void*)1
+ forKey: object];
} @catch (id e) {
[self release];
@throw e;
}
@@ -164,11 +210,10 @@
{
self = [self init];
@try {
void *pool = objc_autoreleasePoolPush();
- OFNumber *one;
OFEnumerator *enumerator;
OFXMLElement *child;
if ((![[element name] isEqual: @"OFSet"] &&
![[element name] isEqual: @"OFMutableSet"]) ||
@@ -175,20 +220,17 @@
![[element namespace] isEqual: OF_SERIALIZATION_NS])
@throw [OFInvalidArgumentException
exceptionWithClass: [self class]
selector: _cmd];
- one = [OFNumber numberWithSize: 1];
-
enumerator = [[element elementsForNamespace:
OF_SERIALIZATION_NS] objectEnumerator];
while ((child = [enumerator nextObject]) != nil) {
void *pool2 = objc_autoreleasePoolPush();
- [dictionary OF_setObject: one
- forKey: [child objectByDeserializing]
- copyKey: NO];
+ [mapTable setValue: (void*)1
+ forKey: [child objectByDeserializing]];
objc_autoreleasePoolPop(pool2);
}
objc_autoreleasePoolPop(pool);
@@ -200,26 +242,26 @@
return self;
}
- (void)dealloc
{
- [dictionary release];
+ [mapTable release];
[super dealloc];
}
- (size_t)count
{
- return [dictionary count];
+ return [mapTable count];
}
- (BOOL)containsObject: (id)object
{
if (object == nil)
return NO;
- return ([dictionary objectForKey: object] != nil);
+ return ([mapTable valueForKey: object] != nil);
}
- (BOOL)isEqual: (id)object
{
OFSet_hashtable *otherSet;
@@ -229,32 +271,40 @@
![object isKindOfClass: [OFCountedSet_hashtable class]])
return [super isEqual: object];
otherSet = object;
- return [otherSet->dictionary isEqual: dictionary];
+ return [otherSet->mapTable isEqual: mapTable];
}
- (OFEnumerator*)objectEnumerator
{
- return [dictionary keyEnumerator];
+ return [[[OFMapTableEnumeratorWrapper alloc]
+ initWithEnumerator: [mapTable keyEnumerator]
+ object: self] autorelease];
}
- (int)countByEnumeratingWithState: (of_fast_enumeration_state_t*)state
objects: (id*)objects
count: (int)count
{
- return [dictionary countByEnumeratingWithState: state
- objects: objects
- count: count];
+ return [mapTable countByEnumeratingWithState: state
+ objects: objects
+ count: count];
}
#ifdef OF_HAVE_BLOCKS
- (void)enumerateObjectsUsingBlock: (of_set_enumeration_block_t)block
{
- [dictionary enumerateKeysAndObjectsUsingBlock: ^ (id key, id object,
- BOOL *stop) {
- block(key, stop);
- }];
+ @try {
+ [mapTable enumerateKeysAndValuesUsingBlock:
+ ^ (void *key, void *value, BOOL *stop) {
+ block(key, stop);
+ }];
+ } @catch (OFEnumerationMutationException *e) {
+ @throw [OFEnumerationMutationException
+ exceptionWithClass: [self class]
+ object: self];
+ }
}
#endif
@end
Index: tests/OFSet.m
==================================================================
--- tests/OFSet.m
+++ tests/OFSet.m
@@ -49,11 +49,11 @@
TEST(@"-[hash]", [set1 hash] == [set2 hash])
TEST(@"-[description]",
[[set1 description]
- isEqual: @"{(\n\tfoo,\n\tbaz,\n\tx,\n\tbar\n)}"] &&
+ isEqual: @"{(\n\tx,\n\tbar,\n\tfoo,\n\tbaz\n)}"] &&
[[set1 description] isEqual: [set2 description]])
TEST(@"-[copy]", [set1 isEqual: [[set1 copy] autorelease]])
TEST(@"-[mutableCopy]",
@@ -96,23 +96,23 @@
i = 0;
for (OFString *s in set1) {
switch (i) {
case 0:
- if (![s isEqual: @"foo"])
+ if (![s isEqual: @"x"])
ok = NO;
break;
case 1:
- if (![s isEqual: @"baz"])
+ if (![s isEqual: @"bar"])
ok = NO;
break;
case 2:
- if (![s isEqual: @"x"])
+ if (![s isEqual: @"foo"])
ok = NO;
break;
case 3:
- if (![s isEqual: @"bar"])
+ if (![s isEqual: @"baz"])
ok = NO;
break;
}
i++;
Index: tests/serialization.xml
==================================================================
--- tests/serialization.xml
+++ tests/serialization.xml
@@ -39,23 +39,23 @@
- foo
bar
+ foo
+
-