Index: src/Makefile ================================================================== --- src/Makefile +++ src/Makefile @@ -9,10 +9,11 @@ SRCS = OFApplication.m \ OFArray.m \ OFAutoreleasePool.m \ OFBlock.m \ + OFCArray.m \ OFConstantString.m \ OFCountedSet.m \ OFDataArray.m \ OFDataArray+Hashing.m \ OFDate.m \ @@ -27,10 +28,11 @@ OFHTTPRequest.m \ OFIntrospection.m \ OFList.m \ OFMD5Hash.m \ OFMutableArray.m \ + OFMutableCArray.m \ OFMutableDictionary.m \ OFMutableSet.m \ OFMutableString.m \ OFNull.m \ OFNumber.m \ Index: src/OFApplication.m ================================================================== --- src/OFApplication.m +++ src/OFApplication.m @@ -198,16 +198,11 @@ arguments = [[OFMutableArray alloc] init]; for (i = 1; i < *argc; i++) [arguments addObject: [OFString stringWithCString: (*argv)[i]]]; - /* - * Class swizzle the arguments to be immutable, as we don't need to - * change them anymore and expose them only as OFArray*. But not - * swizzling it would create a real copy each time -[copy] is called. - */ - arguments->isa = [OFArray class]; + [arguments makeImmutable]; [pool release]; } - (void)getArgumentCount: (int**)argc_ Index: src/OFArray.h ================================================================== --- src/OFArray.h +++ src/OFArray.h @@ -19,11 +19,10 @@ #import "OFObject.h" #import "OFCollection.h" #import "OFEnumerator.h" #import "OFSerialization.h" -@class OFDataArray; @class OFString; #ifdef OF_HAVE_BLOCKS typedef void (^of_array_enumeration_block_t)(id object, size_t index, BOOL *stop); @@ -35,14 +34,10 @@ /** * \brief A class for storing objects in an array. */ @interface OFArray: OFObject -{ - OFDataArray *array; -} - /** * \brief Creates a new OFArray. * * \return A new autoreleased OFArray */ @@ -142,17 +137,10 @@ * \return An initialized OFArray */ - initWithCArray: (id*)objects length: (size_t)length; -/** - * \brief Returns the objects of the array as a C array. - * - * \return The objects of the array as a C array - */ -- (id*)cArray; - /** * \brief Returns a specified object of the array. * * The returned object is not retained and autoreleased for performance * reasons! @@ -160,10 +148,26 @@ * \param index The number of the object to return * \return The specified object of the OFArray */ - (id)objectAtIndex: (size_t)index; +/** + * \brief Copies the objects at the specified range to the specified buffer. + * + * \param buffer The buffer to copy the objects to + * \param range The range to copy + */ +- (void)getObjects: (id*)buffer + inRange: (of_range_t)range; + +/** + * \brief Returns the objects of the array as a C array. + * + * \return The objects of the array as a C array + */ +- (id*)cArray; + /** * \brief Returns the index of the first object that is equivalent to the * specified object or OF_INVALID_INDEX if it was not found. * * \param object The object whose index is returned @@ -210,22 +214,10 @@ * * \return The last object of the array or nil */ - (id)lastObject; -/** - * \brief Returns the objects from the specified index to the specified index as - * a new OFArray. - * - * \param start The index where the subarray starts - * \param end The index where the subarray ends. - * This points BEHIND the last object! - * \return The subarray as a new autoreleased OFArray - */ -- (OFArray*)objectsFromIndex: (size_t)start - toIndex: (size_t)end; - /** * \brief Returns the objects in the specified range as a new OFArray. * * \param range The range for the subarray * \return The subarray as a new autoreleased OFArray @@ -301,22 +293,23 @@ * \return The array folded to a single object */ - (id)foldUsingBlock: (of_array_fold_block_t)block; #endif @end + +@interface OFArrayPlaceholder: OFArray +@end @interface OFArrayEnumerator: OFEnumerator { OFArray *array; - OFDataArray *dataArray; size_t count; unsigned long mutations; unsigned long *mutationsPtr; - size_t pos; + size_t position; } -- initWithArray: (OFArray*)data - dataArray: (OFDataArray*)dataArray - mutationsPointer: (unsigned long*)mutationsPtr; +- initWithArray: (OFArray*)data + mutationsPtr: (unsigned long*)mutationsPtr; @end #import "OFMutableArray.h" Index: src/OFArray.m ================================================================== --- src/OFArray.m +++ src/OFArray.m @@ -17,22 +17,116 @@ #include "config.h" #include #import "OFArray.h" -#import "OFDataArray.h" +#import "OFCArray.h" #import "OFString.h" #import "OFXMLElement.h" #import "OFAutoreleasePool.h" #import "OFEnumerationMutationException.h" #import "OFInvalidArgumentException.h" +#import "OFNotImplementedException.h" #import "OFOutOfRangeException.h" #import "macros.h" + +static struct { + Class isa; +} placeholder; + +@implementation OFArrayPlaceholder +- init +{ + return (id)[[OFCArray alloc] init]; +} + +- initWithObject: (id)object +{ + return (id)[[OFCArray alloc] initWithObject: object]; +} + +- initWithObjects: (id)firstObject, ... +{ + id ret; + va_list arguments; + + va_start(arguments, firstObject); + ret = [[OFCArray alloc] initWithObject: firstObject + arguments: arguments]; + va_end(arguments); + + return ret; +} + +- initWithObject: (id)firstObject + arguments: (va_list)arguments +{ + return (id)[[OFCArray alloc] initWithObject: firstObject + arguments: arguments]; +} + +- initWithArray: (OFArray*)array +{ + return (id)[[OFCArray alloc] initWithArray: array]; +} + +- initWithCArray: (id*)objects +{ + return (id)[[OFCArray alloc] initWithCArray: objects]; +} + +- initWithCArray: (id*)objects + length: (size_t)length +{ + return (id)[[OFCArray alloc] initWithCArray: objects + length: length]; +} + +- initWithSerialization: (OFXMLElement*)element +{ + return (id)[[OFCArray alloc] initWithSerialization: element]; +} + +- retain +{ + return self; +} + +- autorelease +{ + return self; +} + +- (void)release +{ +} + +- (void)dealloc +{ + @throw [OFNotImplementedException newWithClass: isa + selector: _cmd]; + [super dealloc]; /* Get rid of a stupid warning */ +} +@end @implementation OFArray ++ (void)initialize +{ + if (self == [OFArray class]) + placeholder.isa = [OFArrayPlaceholder class]; +} + ++ alloc +{ + if (self == [OFArray class]) + return (id)&placeholder; + + return [super alloc]; +} + + array { return [[[self alloc] init] autorelease]; } @@ -69,37 +163,13 @@ { return [[[self alloc] initWithCArray: objects length: length] autorelease]; } -- init -{ - self = [super init]; - - @try { - array = [[OFDataArray alloc] initWithItemSize: sizeof(id)]; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - - initWithObject: (id)object { - self = [self init]; - - @try { - [array addItem: &object]; - [object retain]; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; + return [self initWithObjects: object, nil]; } - initWithObjects: (id)firstObject, ... { id ret; @@ -114,169 +184,79 @@ } - initWithObject: (id)firstObject arguments: (va_list)arguments { - self = [self init]; - - @try { - id object; - - [array addItem: &firstObject]; - [firstObject retain]; - - while ((object = va_arg(arguments, id)) != nil) { - [array addItem: &object]; - [object retain]; - } - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- initWithArray: (OFArray*)array_ -{ - id *cArray; - size_t i, count; - - self = [self init]; - - @try { - cArray = [array_ cArray]; - count = [array_ count]; - } @catch (id e) { - [self release]; - @throw e; - } - - @try { - for (i = 0; i < count; i++) - [cArray[i] retain]; - - [array addNItems: count - fromCArray: cArray]; - } @catch (id e) { - for (i = 0; i < count; i++) - [cArray[i] release]; - - /* Prevent double-release of objects */ - [array release]; - array = nil; - - [self release]; - @throw e; - } - - return self; + Class c = isa; + [self release]; + @throw [OFNotImplementedException newWithClass: c + selector: _cmd]; +} + +- initWithArray: (OFArray*)array +{ + Class c = isa; + [self release]; + @throw [OFNotImplementedException newWithClass: c + selector: _cmd]; } - initWithCArray: (id*)objects { - self = [self init]; - - @try { - id *object; - size_t count = 0; - - for (object = objects; *object != nil; object++) { - [*object retain]; - count++; - } - - [array addNItems: count - fromCArray: objects]; - } @catch (id e) { - id *object; - - for (object = objects; *object != nil; object++) - [*object release]; - - [self release]; - @throw e; - } - - return self; + Class c = isa; + [self release]; + @throw [OFNotImplementedException newWithClass: c + selector: _cmd]; } - initWithCArray: (id*)objects length: (size_t)length { - self = [self init]; - - @try { - size_t i; - - for (i = 0; i < length; i++) - [objects[i] retain]; - - [array addNItems: length - fromCArray: objects]; - } @catch (id e) { - size_t i; - - for (i = 0; i < length; i++) - [objects[i] release]; - - [self release]; - @throw e; - } - - return self; + Class c = isa; + [self release]; + @throw [OFNotImplementedException newWithClass: c + selector: _cmd]; } - initWithSerialization: (OFXMLElement*)element { - self = [self init]; - - @try { - OFAutoreleasePool *pool, *pool2; - OFEnumerator *enumerator; - OFXMLElement *child; - - pool = [[OFAutoreleasePool alloc] init]; - - if (![[element name] isEqual: [self className]] || - ![[element namespace] isEqual: OF_SERIALIZATION_NS]) - @throw [OFInvalidArgumentException newWithClass: isa - selector: _cmd]; - - enumerator = [[element children] objectEnumerator]; - pool2 = [[OFAutoreleasePool alloc] init]; - - while ((child = [enumerator nextObject]) != nil) { - id object; - - if (![[child namespace] isEqual: OF_SERIALIZATION_NS]) - continue; - - object = [child objectByDeserializing]; - [array addItem: &object]; - [object retain]; - - [pool2 releaseObjects]; - } - - [pool release]; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; + Class c = isa; + [self release]; + @throw [OFNotImplementedException newWithClass: c + selector: _cmd]; } - (size_t)count { - return [array count]; + @throw [OFNotImplementedException newWithClass: isa + selector: _cmd]; +} + +- (void)getObjects: (id*)buffer + inRange: (of_range_t)range +{ + size_t i; + + for (i = 0; i < range.length; i++) + buffer[i] = [self objectAtIndex: range.start + i]; } - (id*)cArray { - return [array cArray]; + OFObject *container; + size_t count; + id *buffer; + + container = [[[OFObject alloc] init] autorelease]; + count = [self count]; + buffer = [container allocMemoryForNItems: [self count] + withSize: sizeof(*buffer)]; + + [self getObjects: buffer + inRange: of_range(0, count)]; + + return buffer; } - copy { return [self retain]; @@ -287,128 +267,109 @@ return [[OFMutableArray alloc] initWithArray: self]; } - (id)objectAtIndex: (size_t)index { - return *((id*)[array itemAtIndex: index]); + @throw [OFNotImplementedException newWithClass: isa + selector: _cmd]; } - (size_t)indexOfObject: (id)object { - id *cArray = [array cArray]; - size_t i, count = [array count]; - - if (cArray == NULL) - return OF_INVALID_INDEX; + size_t i, count = [self count]; for (i = 0; i < count; i++) - if ([cArray[i] isEqual: object]) + if ([[self objectAtIndex: i] isEqual: object]) return i; return OF_INVALID_INDEX; } - (size_t)indexOfObjectIdenticalTo: (id)object { - id *cArray = [array cArray]; - size_t i, count = [array count]; - - if (cArray == NULL) - return OF_INVALID_INDEX; + size_t i, count = [self count]; for (i = 0; i < count; i++) - if (cArray[i] == object) + if ([self objectAtIndex: i] == object) return i; return OF_INVALID_INDEX; } - (BOOL)containsObject: (id)object { - id *cArray = [array cArray]; - size_t i, count = [array count]; - - if (cArray == NULL) - return NO; - - for (i = 0; i < count; i++) - if ([cArray[i] isEqual: object]) - return YES; - - return NO; + return ([self indexOfObject: object] != OF_INVALID_INDEX); } - (BOOL)containsObjectIdenticalTo: (id)object { - id *cArray = [array cArray]; - size_t i, count = [array count]; - - if (cArray == NULL) - return NO; - - for (i = 0; i < count; i++) - if (cArray[i] == object) - return YES; - - return NO; + return ([self indexOfObjectIdenticalTo: object] != OF_INVALID_INDEX); } - (id)firstObject { - id *firstObject = [array firstItem]; + if ([self count] > 0) + return [self objectAtIndex: 0]; - return (firstObject != NULL ? *firstObject : nil); + return nil; } - (id)lastObject { - id *lastObject = [array lastItem]; - - return (lastObject != NULL ? *lastObject : nil); -} - -- (OFArray*)objectsFromIndex: (size_t)start - toIndex: (size_t)end -{ - size_t count = [array count]; - - if (end > count || start > end) - @throw [OFOutOfRangeException newWithClass: isa]; - - return [OFArray arrayWithCArray: (id*)[array cArray] + start - length: end - start]; + size_t count = [self count]; + + if (count > 0) + return [self objectAtIndex: count - 1]; + + return nil; } - (OFArray*)objectsInRange: (of_range_t)range { - return [self objectsFromIndex: range.start - toIndex: range.start + range.length]; + OFArray *ret; + id *buffer = [self allocMemoryForNItems: range.length + withSize: sizeof(*buffer)]; + + @try { + [self getObjects: buffer + inRange: range]; + + ret = [OFArray arrayWithCArray: buffer + length: range.length]; + } @finally { + [self freeMemory: buffer]; + } + + return ret; } - (OFString*)componentsJoinedByString: (OFString*)separator { - OFAutoreleasePool *pool; - OFString *ret; - OFObject **cArray = [array cArray]; - size_t i, count = [array count]; + OFAutoreleasePool *pool, *pool2; + OFMutableString *ret; + id *cArray; + size_t i, count = [self count]; IMP append; if (count == 0) return @""; if (count == 1) - return [cArray[0] description]; + return [[self firstObject] description]; ret = [OFMutableString string]; append = [ret methodForSelector: @selector(appendString:)]; pool = [[OFAutoreleasePool alloc] init]; + cArray = [self cArray]; + + pool2 = [[OFAutoreleasePool alloc] init]; for (i = 0; i < count - 1; i++) { append(ret, @selector(appendString:), [cArray[i] description]); append(ret, @selector(appendString:), separator); - [pool releaseObjects]; + [pool2 releaseObjects]; } append(ret, @selector(appendString:), [cArray[i] description]); [pool release]; @@ -421,38 +382,36 @@ return ret; } - (BOOL)isEqual: (id)object { + /* FIXME: Optimize (for example, buffer of 16 for each) */ OFArray *otherArray; - id *cArray, *otherCArray; size_t i, count; if (![object isKindOfClass: [OFArray class]]) return NO; otherArray = object; - count = [array count]; + count = [self count]; if (count != [otherArray count]) return NO; - cArray = [array cArray]; - otherCArray = [otherArray cArray]; - for (i = 0; i < count; i++) - if (![cArray[i] isEqual: otherCArray[i]]) + if (![[self objectAtIndex: i] isEqual: + [otherArray objectAtIndex: i]]) return NO; return YES; } - (uint32_t)hash { - id *cArray = [array cArray]; - size_t i, count = [array count]; + id *cArray = [self cArray]; + size_t i, count = [self count]; uint32_t hash; OF_HASH_INIT(hash); for (i = 0; i < count; i++) { @@ -472,11 +431,11 @@ - (OFString*)description { OFAutoreleasePool *pool; OFMutableString *ret; - if ([array count] == 0) + if ([self count] == 0) return @"()"; pool = [[OFAutoreleasePool alloc] init]; ret = [[self componentsJoinedByString: @",\n"] mutableCopy]; @@ -506,15 +465,19 @@ - (OFXMLElement*)XMLElementBySerializing { OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; OFAutoreleasePool *pool2; OFXMLElement *element; - id *cArray = [array cArray]; - size_t i, count = [array count]; + id *cArray = [self cArray]; + size_t i, count = [self count]; - element = [OFXMLElement elementWithName: [self className] - namespace: OF_SERIALIZATION_NS]; + if ([self isKindOfClass: [OFMutableArray class]]) + element = [OFXMLElement elementWithName: @"OFMutableArray" + namespace: OF_SERIALIZATION_NS]; + else + element = [OFXMLElement elementWithName: @"OFArray" + namespace: OF_SERIALIZATION_NS]; pool2 = [[OFAutoreleasePool alloc] init]; for (i = 0; i < count; i++) { [element addChild: [cArray[i] XMLElementBySerializing]]; @@ -532,23 +495,23 @@ return element; } - (void)makeObjectsPerformSelector: (SEL)selector { - id *cArray = [array cArray]; - size_t i, count = [array count]; + id *cArray = [self cArray]; + size_t i, count = [self count]; for (i = 0; i < count; i++) ((void(*)(id, SEL))[cArray[i] methodForSelector: selector])(cArray[i], selector); } - (void)makeObjectsPerformSelector: (SEL)selector withObject: (id)object { - id *cArray = [array cArray]; - size_t i, count = [array count]; + id *cArray = [self cArray]; + size_t i, count = [self count]; for (i = 0; i < count; i++) ((void(*)(id, SEL, id))[cArray[i] methodForSelector: selector])(cArray[i], selector, object); } @@ -555,47 +518,46 @@ - (int)countByEnumeratingWithState: (of_fast_enumeration_state_t*)state objects: (id*)objects count: (int)count_ { - size_t count = [array count]; + /* FIXME: Use -[getObjects:inRange:] on the passed objects */ + size_t count = [self count]; if (count > INT_MAX) @throw [OFOutOfRangeException newWithClass: isa]; if (state->state >= count) return 0; state->state = count; - state->itemsPtr = [array cArray]; + state->itemsPtr = [self cArray]; state->mutationsPtr = (unsigned long*)self; return (int)count; } - (OFEnumerator*)objectEnumerator { return [[[OFArrayEnumerator alloc] initWithArray: self - dataArray: array - mutationsPointer: NULL] autorelease]; + mutationsPtr: NULL] autorelease]; } #ifdef OF_HAVE_BLOCKS - (void)enumerateObjectsUsingBlock: (of_array_enumeration_block_t)block { - id *cArray = [array cArray]; - size_t i, count = [array count]; + size_t i, count = [self count]; BOOL stop = NO; for (i = 0; i < count && !stop; i++) - block(cArray[i], i, &stop); + block([self objectAtIndex: i], i, &stop); } - (OFArray*)mappedArrayUsingBlock: (of_array_map_block_t)block { OFArray *ret; - size_t count = [array count]; + size_t count = [self count]; id *tmp = [self allocMemoryForNItems: count withSize: sizeof(id)]; @try { [self enumerateObjectsUsingBlock: ^ (id object, size_t index, @@ -613,11 +575,11 @@ } - (OFArray*)filteredArrayUsingBlock: (of_array_filter_block_t)block { OFArray *ret; - size_t count = [array count]; + size_t count = [self count]; id *tmp = [self allocMemoryForNItems: count withSize: sizeof(id)]; @try { __block size_t i = 0; @@ -637,11 +599,11 @@ return ret; } - (id)foldUsingBlock: (of_array_fold_block_t)block { - size_t count = [array count]; + size_t count = [self count]; __block id current; if (count == 0) return nil; if (count == 1) @@ -665,45 +627,29 @@ }]; return [current autorelease]; } #endif - -- (void)dealloc -{ - id *cArray = [array cArray]; - size_t i, count = [array count]; - - for (i = 0; i < count; i++) - [cArray[i] release]; - - [array release]; - - [super dealloc]; -} @end @implementation OFArrayEnumerator -- initWithArray: (OFArray*)array_ - dataArray: (OFDataArray*)dataArray_ - mutationsPointer: (unsigned long*)mutationsPtr_ +- initWithArray: (OFArray*)array_ + mutationsPtr: (unsigned long*)mutationsPtr_ { self = [super init]; array = [array_ retain]; - dataArray = [dataArray_ retain]; - count = [dataArray count]; + count = [array count]; mutations = (mutationsPtr_ != NULL ? *mutationsPtr_ : 0); mutationsPtr = mutationsPtr_; return self; } - (void)dealloc { [array release]; - [dataArray release]; [super dealloc]; } - (id)nextObject @@ -710,12 +656,12 @@ { if (mutationsPtr != NULL && *mutationsPtr != mutations) @throw [OFEnumerationMutationException newWithClass: isa object: array]; - if (pos < count) - return *(id*)[dataArray itemAtIndex: pos++]; + if (position < count) + return [array objectAtIndex: position++]; return nil; } - (void)reset @@ -722,8 +668,8 @@ { if (mutationsPtr != NULL && *mutationsPtr != mutations) @throw [OFEnumerationMutationException newWithClass: isa object: array]; - pos = 0; + position = 0; } @end ADDED src/OFCArray.h Index: src/OFCArray.h ================================================================== --- src/OFCArray.h +++ src/OFCArray.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011 + * Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#import "OFArray.h" + +@class OFDataArray; + +/** + * \brief A class for storing objects in an array. + */ +@interface OFCArray: OFArray +{ + OFDataArray *array; +} +@end ADDED src/OFCArray.m Index: src/OFCArray.m ================================================================== --- src/OFCArray.m +++ src/OFCArray.m @@ -0,0 +1,356 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011 + * Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#include + +#import "OFCArray.h" +#import "OFMutableCArray.h" +#import "OFDataArray.h" +#import "OFString.h" +#import "OFXMLElement.h" +#import "OFAutoreleasePool.h" + +#import "OFEnumerationMutationException.h" +#import "OFInvalidArgumentException.h" +#import "OFOutOfRangeException.h" + +#import "macros.h" + +@implementation OFCArray +- init +{ + self = [super init]; + + @try { + array = [[OFDataArray alloc] initWithItemSize: sizeof(id)]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- initWithObject: (id)object +{ + self = [self init]; + + @try { + [array addItem: &object]; + [object retain]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- initWithObject: (id)firstObject + arguments: (va_list)arguments +{ + self = [self init]; + + @try { + id object; + + [array addItem: &firstObject]; + [firstObject retain]; + + while ((object = va_arg(arguments, id)) != nil) { + [array addItem: &object]; + [object retain]; + } + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- initWithArray: (OFArray*)array_ +{ + id *cArray; + size_t i, count; + + self = [self init]; + + @try { + cArray = [array_ cArray]; + count = [array_ count]; + } @catch (id e) { + [self release]; + @throw e; + } + + @try { + for (i = 0; i < count; i++) + [cArray[i] retain]; + + [array addNItems: count + fromCArray: cArray]; + } @catch (id e) { + for (i = 0; i < count; i++) + [cArray[i] release]; + + /* Prevent double-release of objects */ + [array release]; + array = nil; + + [self release]; + @throw e; + } + + return self; +} + +- initWithCArray: (id*)objects +{ + self = [self init]; + + @try { + id *object; + size_t count = 0; + + for (object = objects; *object != nil; object++) { + [*object retain]; + count++; + } + + [array addNItems: count + fromCArray: objects]; + } @catch (id e) { + id *object; + + for (object = objects; *object != nil; object++) + [*object release]; + + [self release]; + @throw e; + } + + return self; +} + +- initWithCArray: (id*)objects + length: (size_t)length +{ + self = [self init]; + + @try { + size_t i; + + for (i = 0; i < length; i++) + [objects[i] retain]; + + [array addNItems: length + fromCArray: objects]; + } @catch (id e) { + size_t i; + + for (i = 0; i < length; i++) + [objects[i] release]; + + [self release]; + @throw e; + } + + return self; +} + +- initWithSerialization: (OFXMLElement*)element +{ + self = [self init]; + + @try { + OFAutoreleasePool *pool, *pool2; + OFEnumerator *enumerator; + OFXMLElement *child; + + pool = [[OFAutoreleasePool alloc] init]; + + if ((![[element name] isEqual: @"OFArray"] && + ![[element name] isEqual: @"OFMutableArray"]) || + ![[element namespace] isEqual: OF_SERIALIZATION_NS]) + @throw [OFInvalidArgumentException newWithClass: isa + selector: _cmd]; + + enumerator = [[element children] objectEnumerator]; + pool2 = [[OFAutoreleasePool alloc] init]; + + while ((child = [enumerator nextObject]) != nil) { + id object; + + if (![[child namespace] isEqual: OF_SERIALIZATION_NS]) + continue; + + object = [child objectByDeserializing]; + [array addItem: &object]; + [object retain]; + + [pool2 releaseObjects]; + } + + [pool release]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (size_t)count +{ + return [array count]; +} + +- (id*)cArray +{ + return [array cArray]; +} + +- (id)objectAtIndex: (size_t)index +{ + return *((id*)[array itemAtIndex: index]); +} + +- (void)getObjects: (id*)buffer + inRange: (of_range_t)range +{ + id *cArray = [array cArray]; + size_t i, count = [array count]; + + if (range.start + range.length > count) + @throw [OFOutOfRangeException newWithClass: isa]; + + for (i = 0; i < range.length; i++) + buffer[i] = cArray[range.start + i]; +} + +- (size_t)indexOfObject: (id)object +{ + id *cArray = [array cArray]; + size_t i, count = [array count]; + + for (i = 0; i < count; i++) + if ([cArray[i] isEqual: object]) + return i; + + return OF_INVALID_INDEX; +} + +- (size_t)indexOfObjectIdenticalTo: (id)object +{ + id *cArray = [array cArray]; + size_t i, count = [array count]; + + for (i = 0; i < count; i++) + if (cArray[i] == object) + return i; + + return OF_INVALID_INDEX; +} + + +- (OFArray*)objectsInRange: (of_range_t)range +{ + size_t count = [array count]; + + if (range.start + range.length > count) + @throw [OFOutOfRangeException newWithClass: isa]; + + return [OFArray arrayWithCArray: (id*)[array cArray] + range.start + length: range.length]; +} + +- (BOOL)isEqual: (id)object +{ + OFArray *otherArray; + id *cArray, *otherCArray; + size_t i, count; + + if (![object isKindOfClass: [OFCArray class]] && + ![object isKindOfClass: [OFMutableCArray class]]) + return [super isEqual: object]; + + otherArray = object; + + count = [array count]; + + if (count != [otherArray count]) + return NO; + + cArray = [array cArray]; + otherCArray = [otherArray cArray]; + + for (i = 0; i < count; i++) + if (![cArray[i] isEqual: otherCArray[i]]) + return NO; + + return YES; +} + +- (uint32_t)hash +{ + id *cArray = [array cArray]; + size_t i, count = [array count]; + uint32_t hash; + + OF_HASH_INIT(hash); + + for (i = 0; i < count; i++) { + uint32_t h = [cArray[i] hash]; + + 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); + + return hash; +} + +#ifdef OF_HAVE_BLOCKS +- (void)enumerateObjectsUsingBlock: (of_array_enumeration_block_t)block +{ + id *cArray = [array cArray]; + size_t i, count = [array count]; + BOOL stop = NO; + + for (i = 0; i < count && !stop; i++) + block(cArray[i], i, &stop); +} +#endif + +- (void)dealloc +{ + id *cArray = [array cArray]; + size_t i, count = [array count]; + + for (i = 0; i < count; i++) + [cArray[i] release]; + + [array release]; + + [super dealloc]; +} +@end Index: src/OFFile.m ================================================================== --- src/OFFile.m +++ src/OFFile.m @@ -301,17 +301,11 @@ } [pool release]; #endif - /* - * Class swizzle the array to be immutable. We declared the return type - * to be OFArray*, so it can't be modified anyway. But not swizzling it - * would create a real copy each time -[copy] is called. - */ - files->isa = [OFArray class]; - return files; + return [files makeImmutable]; } + (void)changeToDirectory: (OFString*)path { if (chdir([path cString])) Index: src/OFIntrospection.m ================================================================== --- src/OFIntrospection.m +++ src/OFIntrospection.m @@ -165,12 +165,12 @@ _initWithMethod: &methodList->method_list[i]] autorelease]]; } #endif - classMethods->isa = [OFArray class]; - instanceMethods->isa = [OFArray class]; + [classMethods makeImmutable]; + [instanceMethods makeImmutable]; [pool release]; } @catch (id e) { [self release]; @throw e; Index: src/OFMutableArray.h ================================================================== --- src/OFMutableArray.h +++ src/OFMutableArray.h @@ -22,14 +22,10 @@ /** * \brief A class for storing, adding and removing objects in an array. */ @interface OFMutableArray: OFArray -{ - unsigned long mutations; -} - /** * \brief Adds an object to the OFArray. * * \param object An object to add */ @@ -101,17 +97,15 @@ * \param nObjects The number of objects to remove */ - (void)removeNObjects: (size_t)nObjects; /** - * \brief Removes the specified amount of objects at the specified index. + * \brief Removes the object in the specified range. * - * \param nobjects The number of objects to remove - * \param index The index at which the objects are removed + * \param range The range of the objects to remove */ -- (void)removeNObjects: (size_t)nObjects - atIndex: (size_t)index; +- (void)removeObjectsInRange: (of_range_t)range; /** * \brief Removes the last object. */ - (void)removeLastObject; @@ -122,6 +116,14 @@ * * \param block The block which returns a new object for each object */ - (void)replaceObjectsUsingBlock: (of_array_replace_block_t)block; #endif + +/** + * \brief Converts the mutable array to an immutable array. + */ +- (OFArray*)makeImmutable; +@end + +@interface OFMutableArrayPlaceholder: OFMutableArray @end Index: src/OFMutableArray.m ================================================================== --- src/OFMutableArray.m +++ src/OFMutableArray.m @@ -17,253 +17,231 @@ #include "config.h" #include #import "OFMutableArray.h" -#import "OFDataArray.h" +#import "OFMutableCArray.h" #import "OFAutoreleasePool.h" #import "OFEnumerationMutationException.h" #import "OFInvalidArgumentException.h" +#import "OFNotImplementedException.h" #import "OFOutOfRangeException.h" + +#import "macros.h" + +static struct { + Class isa; +} placeholder; + +@implementation OFMutableArrayPlaceholder +- init +{ + return (id)[[OFMutableCArray alloc] init]; +} + +- initWithObject: (id)object +{ + return (id)[[OFMutableCArray alloc] initWithObject: object]; +} + +- initWithObjects: (id)firstObject, ... +{ + id ret; + va_list arguments; + + va_start(arguments, firstObject); + ret = [[OFMutableCArray alloc] initWithObject: firstObject + arguments: arguments]; + va_end(arguments); + + return ret; +} + +- initWithObject: (id)firstObject + arguments: (va_list)arguments +{ + return (id)[[OFMutableCArray alloc] initWithObject: firstObject + arguments: arguments]; +} + +- initWithArray: (OFArray*)array +{ + return (id)[[OFMutableCArray alloc] initWithArray: array]; +} + +- initWithCArray: (id*)objects +{ + return (id)[[OFMutableCArray alloc] initWithCArray: objects]; +} + +- initWithCArray: (id*)objects + length: (size_t)length +{ + return (id)[[OFMutableCArray alloc] initWithCArray: objects + length: length]; +} + +- initWithSerialization: (OFXMLElement*)element +{ + return (id)[[OFMutableCArray alloc] initWithSerialization: element]; +} + +- retain +{ + return self; +} + +- autorelease +{ + return self; +} + +- (void)release +{ +} + +- (void)dealloc +{ + @throw [OFNotImplementedException newWithClass: isa + selector: _cmd]; + [super dealloc]; /* Get rid of a stupid warning */ +} +@end @implementation OFMutableArray ++ (void)initialize +{ + if (self == [OFMutableArray class]) + placeholder.isa = [OFMutableArrayPlaceholder class]; +} + ++ alloc +{ + if (self == [OFMutableArray class]) + return (id)&placeholder; + + return [super alloc]; +} + - copy { return [[OFArray alloc] initWithArray: self]; } - (void)addObject: (id)object { - [array addItem: &object]; - [object retain]; - - mutations++; + [self addObject: object + atIndex: [self count]]; } - (void)addObject: (id)object atIndex: (size_t)index { - [array addItem: &object - atIndex: index]; - [object retain]; + @throw [OFNotImplementedException newWithClass: isa + selector: _cmd]; +} - mutations++; +- (void)replaceObjectAtIndex: (size_t)index + withObject: (id)object +{ + @throw [OFNotImplementedException newWithClass: isa + selector: _cmd]; } - (void)replaceObject: (id)oldObject withObject: (id)newObject { - id *cArray = [array cArray]; - size_t i, count = [array count]; + size_t i, count = [self count]; for (i = 0; i < count; i++) { - if ([cArray[i] isEqual: oldObject]) { - [newObject retain]; - [cArray[i] release]; - cArray[i] = newObject; - + if ([[self objectAtIndex: i] isEqual: oldObject]) { + [self replaceObjectAtIndex: i + withObject: newObject]; return; } } } -- (void)replaceObjectAtIndex: (size_t)index - withObject: (id)object -{ - id *cArray = [array cArray]; - id oldObject; - - if (index >= [array count]) - @throw [OFOutOfRangeException newWithClass: isa]; - - oldObject = cArray[index]; - cArray[index] = [object retain]; - [oldObject release]; -} - - (void)replaceObjectIdenticalTo: (id)oldObject withObject: (id)newObject { - id *cArray = [array cArray]; - size_t i, count = [array count]; - - for (i = 0; i < count; i++) { - if (cArray[i] == oldObject) { - [newObject retain]; - [cArray[i] release]; - cArray[i] = newObject; - - return; - } - } -} - -- (void)removeObject: (id)object -{ - id *cArray = [array cArray]; - size_t i, count = [array count]; - - for (i = 0; i < count; i++) { - if ([cArray[i] isEqual: object]) { - object = cArray[i]; - - [array removeItemAtIndex: i]; - mutations++; - - [object release]; - - return; - } - } -} - -- (void)removeObjectIdenticalTo: (id)object -{ - id *cArray = [array cArray]; - size_t i, count = [array count]; - - for (i = 0; i < count; i++) { - if (cArray[i] == object) { - [array removeItemAtIndex: i]; - mutations++; - - [object release]; + size_t i, count = [self count]; + + for (i = 0; i < count; i++) { + if ([self objectAtIndex: i] == oldObject) { + [self replaceObjectAtIndex: i + withObject: newObject]; return; } } } - (void)removeObjectAtIndex: (size_t)index { - id object = [self objectAtIndex: index]; - [array removeItemAtIndex: index]; - [object release]; - - mutations++; -} - -- (void)removeNObjects: (size_t)nObjects -{ - id *cArray = [array cArray], *copy; - size_t i, count = [array count]; - - if (nObjects > count) - @throw [OFOutOfRangeException newWithClass: isa]; - - copy = [self allocMemoryForNItems: nObjects - withSize: sizeof(id)]; - memcpy(copy, cArray + (count - nObjects), nObjects * sizeof(id)); - - @try { - [array removeNItems: nObjects]; - mutations++; - - for (i = 0; i < nObjects; i++) - [copy[i] release]; - } @finally { - [self freeMemory: copy]; - } -} - -- (void)removeNObjects: (size_t)nObjects - atIndex: (size_t)index -{ - id *cArray = [array cArray], *copy; - size_t i, count = [array count]; - - if (nObjects > count - index) - @throw [OFOutOfRangeException newWithClass: isa]; - - copy = [self allocMemoryForNItems: nObjects - withSize: sizeof(id)]; - memcpy(copy, cArray + index, nObjects * sizeof(id)); - - @try { - [array removeNItems: nObjects - atIndex: index]; - mutations++; - - for (i = 0; i < nObjects; i++) - [copy[i] release]; - } @finally { - [self freeMemory: copy]; - } + @throw [OFNotImplementedException newWithClass: isa + selector: _cmd]; +} + +- (void)removeObject: (id)object +{ + size_t i, count = [self count]; + + for (i = 0; i < count; i++) { + if ([[self objectAtIndex: i] isEqual: object]) { + [self removeObjectAtIndex: i]; + + return; + } + } +} + +- (void)removeObjectIdenticalTo: (id)object +{ + size_t i, count = [self count]; + + for (i = 0; i < count; i++) { + if ([self objectAtIndex: i] == object) { + [self removeObjectAtIndex: i]; + + return; + } + } +} + +- (void)removeNObjects: (size_t)nObjects +{ + size_t count = [self count]; + + [self removeObjectsInRange: of_range(count - nObjects, nObjects)]; +} + +- (void)removeObjectsInRange: (of_range_t)range +{ + size_t i; + + for (i = 0; i < range.length; i++) + [self removeObjectAtIndex: range.start]; } - (void)removeLastObject { - id object = [self objectAtIndex: [array count] - 1]; - [array removeLastItem]; - [object release]; - - mutations++; -} - -- (int)countByEnumeratingWithState: (of_fast_enumeration_state_t*)state - objects: (id*)objects - count: (int)count_ -{ - int ret = [super countByEnumeratingWithState: state - objects: objects - count: count_]; - - state->mutationsPtr = &mutations; - - return ret; -} - -- (OFEnumerator*)objectEnumerator -{ - return [[[OFArrayEnumerator alloc] - initWithArray: self - dataArray: array - mutationsPointer: &mutations] autorelease]; + [self removeNObjects: 1]; } #ifdef OF_HAVE_BLOCKS -- (void)enumerateObjectsUsingBlock: (of_array_enumeration_block_t)block -{ - id *cArray = [array cArray]; - size_t i, count = [array count]; - BOOL stop = NO; - unsigned long mutations2 = mutations; - - for (i = 0; i < count && !stop; i++) { - if (mutations != mutations2) - @throw [OFEnumerationMutationException - newWithClass: isa - object: self]; - - block(cArray[i], i, &stop); - } -} - - (void)replaceObjectsUsingBlock: (of_array_replace_block_t)block { - id *cArray = [array cArray]; - size_t i, count = [array count]; - BOOL stop = NO; - unsigned long mutations2 = mutations; - - for (i = 0; i < count && !stop; i++) { - id newObject; - - if (mutations != mutations2) - @throw [OFEnumerationMutationException - newWithClass: isa - object: self]; - - newObject = block(cArray[i], i, &stop); - - if (newObject == nil) - @throw [OFInvalidArgumentException newWithClass: isa - selector: _cmd]; - - [newObject retain]; - [cArray[i] release]; - cArray[i] = newObject; - } + [self enumerateObjectsUsingBlock: ^ (id object, size_t index, + BOOL *stop) { + [self replaceObjectAtIndex: index + withObject: block(object, index, stop)]; + }]; } #endif + +- (OFArray*)makeImmutable +{ + return self; +} @end ADDED src/OFMutableCArray.h Index: src/OFMutableCArray.h ================================================================== --- src/OFMutableCArray.h +++ src/OFMutableCArray.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011 + * Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#import "OFArray.h" + +@class OFDataArray; + +/** + * \brief A class for storing, adding and removing objects in an array. + */ +@interface OFMutableCArray: OFMutableArray +{ + OFDataArray *array; + unsigned long mutations; +} +@end ADDED src/OFMutableCArray.m Index: src/OFMutableCArray.m ================================================================== --- src/OFMutableCArray.m +++ src/OFMutableCArray.m @@ -0,0 +1,275 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011 + * Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#include + +#import "OFMutableCArray.h" +#import "OFCArray.h" +#import "OFDataArray.h" +#import "OFAutoreleasePool.h" + +#import "OFEnumerationMutationException.h" +#import "OFInvalidArgumentException.h" +#import "OFOutOfRangeException.h" + +@implementation OFMutableCArray ++ (void)initialize +{ + if (self == [OFMutableCArray class]) + [self inheritMethodsFromClass: [OFCArray class]]; +} + +- (void)addObject: (id)object +{ + [array addItem: &object]; + [object retain]; + + mutations++; +} + +- (void)addObject: (id)object + atIndex: (size_t)index +{ + [array addItem: &object + atIndex: index]; + [object retain]; + + mutations++; +} + +- (void)replaceObject: (id)oldObject + withObject: (id)newObject +{ + id *cArray = [array cArray]; + size_t i, count = [array count]; + + for (i = 0; i < count; i++) { + if ([cArray[i] isEqual: oldObject]) { + [newObject retain]; + [cArray[i] release]; + cArray[i] = newObject; + + return; + } + } +} + +- (void)replaceObjectAtIndex: (size_t)index + withObject: (id)object +{ + id *cArray = [array cArray]; + id oldObject; + + if (index >= [array count]) + @throw [OFOutOfRangeException newWithClass: isa]; + + oldObject = cArray[index]; + cArray[index] = [object retain]; + [oldObject release]; +} + +- (void)replaceObjectIdenticalTo: (id)oldObject + withObject: (id)newObject +{ + id *cArray = [array cArray]; + size_t i, count = [array count]; + + for (i = 0; i < count; i++) { + if (cArray[i] == oldObject) { + [newObject retain]; + [cArray[i] release]; + cArray[i] = newObject; + + return; + } + } +} + +- (void)removeObject: (id)object +{ + id *cArray = [array cArray]; + size_t i, count = [array count]; + + for (i = 0; i < count; i++) { + if ([cArray[i] isEqual: object]) { + object = cArray[i]; + + [array removeItemAtIndex: i]; + mutations++; + + [object release]; + + return; + } + } +} + +- (void)removeObjectIdenticalTo: (id)object +{ + id *cArray = [array cArray]; + size_t i, count = [array count]; + + for (i = 0; i < count; i++) { + if (cArray[i] == object) { + [array removeItemAtIndex: i]; + mutations++; + + [object release]; + + return; + } + } +} + +- (void)removeObjectAtIndex: (size_t)index +{ + id object = [self objectAtIndex: index]; + [array removeItemAtIndex: index]; + [object release]; + + mutations++; +} + +- (void)removeNObjects: (size_t)nObjects +{ + id *cArray = [array cArray], *copy; + size_t i, count = [array count]; + + if (nObjects > count) + @throw [OFOutOfRangeException newWithClass: isa]; + + copy = [self allocMemoryForNItems: nObjects + withSize: sizeof(id)]; + memcpy(copy, cArray + (count - nObjects), nObjects * sizeof(id)); + + @try { + [array removeNItems: nObjects]; + mutations++; + + for (i = 0; i < nObjects; i++) + [copy[i] release]; + } @finally { + [self freeMemory: copy]; + } +} + +- (void)removeObjectsInRange: (of_range_t)range +{ + id *cArray = [array cArray], *copy; + size_t i, count = [array count]; + + if (range.length > count - range.start) + @throw [OFOutOfRangeException newWithClass: isa]; + + copy = [self allocMemoryForNItems: range.length + withSize: sizeof(id)]; + memcpy(copy, cArray + range.start, range.length * sizeof(id)); + + @try { + [array removeNItems: range.length + atIndex: range.start]; + mutations++; + + for (i = 0; i < range.length; i++) + [copy[i] release]; + } @finally { + [self freeMemory: copy]; + } +} + +- (void)removeLastObject +{ + id object = [self objectAtIndex: [array count] - 1]; + [array removeLastItem]; + [object release]; + + mutations++; +} + +- (int)countByEnumeratingWithState: (of_fast_enumeration_state_t*)state + objects: (id*)objects + count: (int)count_ +{ + int ret = [super countByEnumeratingWithState: state + objects: objects + count: count_]; + + state->mutationsPtr = &mutations; + + return ret; +} + +- (OFEnumerator*)objectEnumerator +{ + return [[[OFArrayEnumerator alloc] + initWithArray: self + mutationsPtr: &mutations] autorelease]; +} + +#ifdef OF_HAVE_BLOCKS +- (void)enumerateObjectsUsingBlock: (of_array_enumeration_block_t)block +{ + id *cArray = [array cArray]; + size_t i, count = [array count]; + BOOL stop = NO; + unsigned long mutations2 = mutations; + + for (i = 0; i < count && !stop; i++) { + if (mutations != mutations2) + @throw [OFEnumerationMutationException + newWithClass: isa + object: self]; + + block(cArray[i], i, &stop); + } +} + +- (void)replaceObjectsUsingBlock: (of_array_replace_block_t)block +{ + id *cArray = [array cArray]; + size_t i, count = [array count]; + BOOL stop = NO; + unsigned long mutations2 = mutations; + + for (i = 0; i < count && !stop; i++) { + id newObject; + + if (mutations != mutations2) + @throw [OFEnumerationMutationException + newWithClass: isa + object: self]; + + newObject = block(cArray[i], i, &stop); + + if (newObject == nil) + @throw [OFInvalidArgumentException newWithClass: isa + selector: _cmd]; + + [newObject retain]; + [cArray[i] release]; + cArray[i] = newObject; + } +} +#endif + +- (OFArray*)makeImmutable +{ + isa = [OFCArray class]; + return self; +} +@end Index: src/OFString.m ================================================================== --- src/OFString.m +++ src/OFString.m @@ -1581,17 +1581,11 @@ } [array addObject: [OFString stringWithCString: s->cString + last]]; [pool release]; - /* - * Class swizzle the array to be immutable. We declared the return type - * to be OFArray*, so it can't be modified anyway. But not swizzling it - * would create a real copy each time -[copy] is called. - */ - array->isa = [OFArray class]; - return array; + return [array makeImmutable]; } - (OFArray*)pathComponents { OFMutableArray *ret; @@ -1629,17 +1623,11 @@ [ret addObject: [OFString stringWithCString: s->cString + last length: i - last]]; [pool release]; - /* - * Class swizzle the array to be immutable. We declared the return type - * to be OFArray*, so it can't be modified anyway. But not swizzling it - * would create a real copy each time -[copy] is called. - */ - ret->isa = [OFArray class]; - return ret; + return [ret makeImmutable]; } - (OFString*)lastPathComponent { size_t pathCStringLength = s->cStringLength; Index: src/OFXMLElement.m ================================================================== --- src/OFXMLElement.m +++ src/OFXMLElement.m @@ -1034,17 +1034,11 @@ for (i = 0; i < count; i++) if (cArray[i]->name != nil) [ret addObject: cArray[i]]; - /* - * Class swizzle the array to be immutable. We declared the return type - * to be OFArray*, so it can't be modified anyway. But not swizzling it - * would create a real copy each time -[copy] is called. - */ - ret->isa = [OFArray class]; - return ret; + return [ret makeImmutable]; } - (OFArray*)elementsForName: (OFString*)elementName { OFMutableArray *ret = [OFMutableArray array]; @@ -1054,17 +1048,11 @@ for (i = 0; i < count; i++) if (cArray[i]->ns == nil && [cArray[i]->name isEqual: elementName]) [ret addObject: cArray[i]]; - /* - * Class swizzle the array to be immutable. We declared the return type - * to be OFArray*, so it can't be modified anyway. But not swizzling it - * would create a real copy each time -[copy] is called. - */ - ret->isa = [OFArray class]; - return ret; + return [ret makeImmutable]; } - (OFArray*)elementsForNamespace: (OFString*)elementNS { OFMutableArray *ret = [OFMutableArray array]; @@ -1074,17 +1062,11 @@ for (i = 0; i < count; i++) if (cArray[i]->name != nil && [cArray[i]->ns isEqual: elementNS]) [ret addObject: cArray[i]]; - /* - * Class swizzle the array to be immutable. We declared the return type - * to be OFArray*, so it can't be modified anyway. But not swizzling it - * would create a real copy each time -[copy] is called. - */ - ret->isa = [OFArray class]; - return ret; + return [ret makeImmutable]; } - (OFArray*)elementsForName: (OFString*)elementName namespace: (OFString*)elementNS { @@ -1102,17 +1084,11 @@ for (i = 0; i < count; i++) if ([cArray[i]->ns isEqual: elementNS] && [cArray[i]->name isEqual: elementName]) [ret addObject: cArray[i]]; - /* - * Class swizzle the array to be immutable. We declared the return type - * to be OFArray*, so it can't be modified anyway. But not swizzling it - * would create a real copy each time -[copy] is called. - */ - ret->isa = [OFArray class]; - return ret; + return [ret makeImmutable]; } - (BOOL)isEqual: (id)object { OFXMLElement *otherElement; Index: tests/OFArrayTests.m ================================================================== --- tests/OFArrayTests.m +++ tests/OFArrayTests.m @@ -83,23 +83,22 @@ TEST(@"-[containsObject:]", [a[0] containsObject: c_ary[1]] == YES && [a[0] containsObject: @"nonexistant"] == NO) - TEST(@"-[containsObject:]", + TEST(@"-[containsObjectIdenticalTo:]", [a[0] containsObjectIdenticalTo: c_ary[1]] == YES && [a[0] containsObjectIdenticalTo: [OFString stringWithString: c_ary[1]]] == NO) TEST(@"-[indexOfObject:]", [a[0] indexOfObject: c_ary[1]] == 1) TEST(@"-[indexOfObjectIdenticalTo:]", [a[1] indexOfObjectIdenticalTo: c_ary[1]] == 1) - TEST(@"-[objectsFromIndex:toIndex", - [[a[0] objectsFromIndex: 1 - toIndex: 3] isEqual: + TEST(@"-[objectsInRange:]", + [[a[0] objectsInRange: of_range(1, 2)] isEqual: ([OFArray arrayWithObjects: c_ary[1], c_ary[2], nil])]) TEST(@"-[replaceObject:withObject:]", R([m[0] replaceObject: c_ary[1] withObject: c_ary[0]]) && @@ -135,18 +134,18 @@ m[1] = [[a[0] mutableCopy] autorelease]; TEST(@"-[removeObjectAtIndex:]", R([m[1] removeObjectAtIndex: 1]) && [m[1] count] == 2 && [[m[1] objectAtIndex: 1] isEqual: c_ary[2]]) m[1] = [[a[0] mutableCopy] autorelease]; - TEST(@"-[removeNObjects:atIndex:]", R([m[1] removeNObjects: 2 - atIndex: 0]) && + TEST(@"-[removeObjectsInRange:]", + R([m[1] removeObjectsInRange: of_range(0, 2)]) && [m[1] count] == 1 && [[m[1] objectAtIndex: 0] isEqual: c_ary[2]]) EXPECT_EXCEPTION(@"Detect out of range in -[objectAtIndex:]", OFOutOfRangeException, [a[0] objectAtIndex: [a[0] count]]) - EXPECT_EXCEPTION(@"Detect out of range in -[removeNItems:]", + EXPECT_EXCEPTION(@"Detect out of range in -[removeNObjects:]", OFOutOfRangeException, [m[0] removeNObjects: [m[0] count] + 1]) TEST(@"-[componentsJoinedByString:]", (a[1] = [OFArray arrayWithObjects: @"foo", @"bar", @"baz", nil]) && [[a[1] componentsJoinedByString: @" "] isEqual: @"foo bar baz"] && @@ -202,16 +201,20 @@ withObject: c_ary[1]]; [m[0] replaceObjectAtIndex: 2 withObject: c_ary[2]]; ok = NO; + i = 0; @try { - for (OFString *s in m[0]) - [m[0] addObject: @""]; + for (OFString *s in m[0]) { + if (i == 0) + [m[0] addObject: @""]; + i++; + } } @catch (OFEnumerationMutationException *e) { ok = YES; - [e dealloc]; + [e release]; } TEST(@"Detection of mutation during Fast Enumeration", ok) [m[0] removeNObjects: 1]; @@ -244,11 +247,17 @@ ^ (id obj, size_t idx, BOOL *stop) { [a2 removeObjectAtIndex: idx]; }]; } @catch (OFEnumerationMutationException *e) { ok = YES; - [e dealloc]; + [e release]; + } @catch (OFOutOfRangeException *e) { + /* + * Out of bounds access due to enumeration not being + * detected. + */ + [e release]; } TEST(@"Detection of mutation during enumeration using blocks", ok) }