Artifact 1b7e4a8b63ae73ff8f287b1d50f9b2098520e1c55b1403eab6607d8dc6e035f6:
- File
src/OFArray.m
— part of check-in
[3d16a30f41]
at
2013-06-22 12:12:36
on branch trunk
— Rework exceptions.
This mostly removes the argument for the class in which the exception
occurred. As backtraces were recently added for all platforms, the
passed class does not give any extra information on where the exception
occurred anymore.This also removes a few other arguments which were not too helpful. In
the past, the idea was to pass as many arguments as possible so that it
is easier to find the origin of the exception. However, as backtraces
are a much better way to find the origin, those are not useful anymore
and just make the exception more cumbersome to use. The rule is now to
only pass arguments that might help in recovering from the exception or
provide information that is otherwise not easily accessible. (user: js, size: 16114) [annotate] [blame] [check-ins using]
/* * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 * Jonathan Schleifer <js@webkeks.org> * * 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 <stdarg.h> #include <stdlib.h> #include <assert.h> #import "OFArray.h" #import "OFArray_subarray.h" #import "OFArray_adjacent.h" #import "OFString.h" #import "OFXMLElement.h" #import "OFDataArray.h" #import "OFEnumerationMutationException.h" #import "OFInvalidArgumentException.h" #import "OFOutOfRangeException.h" #import "autorelease.h" #import "macros.h" static struct { Class isa; } placeholder; @interface OFArray_placeholder: OFArray @end @implementation OFArray_placeholder - init { return (id)[[OFArray_adjacent alloc] init]; } - initWithObject: (id)object { return (id)[[OFArray_adjacent alloc] initWithObject: object]; } - initWithObjects: (id)firstObject, ... { id ret; va_list arguments; va_start(arguments, firstObject); ret = [[OFArray_adjacent alloc] initWithObject: firstObject arguments: arguments]; va_end(arguments); return ret; } - initWithObject: (id)firstObject arguments: (va_list)arguments { return (id)[[OFArray_adjacent alloc] initWithObject: firstObject arguments: arguments]; } - initWithArray: (OFArray*)array { return (id)[[OFArray_adjacent alloc] initWithArray: array]; } - initWithObjects: (id const*)objects count: (size_t)count { return (id)[[OFArray_adjacent alloc] initWithObjects: objects count: count]; } - initWithSerialization: (OFXMLElement*)element { return (id)[[OFArray_adjacent alloc] initWithSerialization: element]; } - retain { return self; } - autorelease { return self; } - (void)release { } - (void)dealloc { [self doesNotRecognizeSelector: _cmd]; abort(); /* Get rid of a stupid warning */ [super dealloc]; } @end @implementation OFArray + (void)initialize { if (self == [OFArray class]) placeholder.isa = [OFArray_placeholder class]; } + alloc { if (self == [OFArray class]) return (id)&placeholder; return [super alloc]; } + (instancetype)array { return [[[self alloc] init] autorelease]; } + (instancetype)arrayWithObject: (id)object { return [[[self alloc] initWithObject: object] autorelease]; } + (instancetype)arrayWithObjects: (id)firstObject, ... { id ret; va_list arguments; va_start(arguments, firstObject); ret = [[[self alloc] initWithObject: firstObject arguments: arguments] autorelease]; va_end(arguments); return ret; } + (instancetype)arrayWithArray: (OFArray*)array { return [[[self alloc] initWithArray: array] autorelease]; } + (instancetype)arrayWithObjects: (id const*)objects count: (size_t)count { return [[[self alloc] initWithObjects: objects count: count] autorelease]; } - init { if (object_getClass(self) == [OFArray class]) { @try { [self doesNotRecognizeSelector: _cmd]; } @catch (id e) { [self release]; @throw e; } abort(); } return [super init]; } - initWithObject: (id)object { if (object == nil) { [self release]; @throw [OFInvalidArgumentException exception]; } return [self initWithObjects: object, nil]; } - initWithObjects: (id)firstObject, ... { id ret; va_list arguments; va_start(arguments, firstObject); ret = [self initWithObject: firstObject arguments: arguments]; va_end(arguments); return ret; } - initWithObject: (id)firstObject arguments: (va_list)arguments { @try { [self doesNotRecognizeSelector: _cmd]; } @catch (id e) { [self release]; @throw e; } abort(); } - initWithArray: (OFArray*)array { @try { [self doesNotRecognizeSelector: _cmd]; } @catch (id e) { [self release]; @throw e; } abort(); } - initWithObjects: (id const*)objects count: (size_t)count { @try { [self doesNotRecognizeSelector: _cmd]; } @catch (id e) { [self release]; @throw e; } abort(); } - initWithSerialization: (OFXMLElement*)element { @try { [self doesNotRecognizeSelector: _cmd]; } @catch (id e) { [self release]; @throw e; } abort(); } - (size_t)count { [self doesNotRecognizeSelector: _cmd]; abort(); } - (void)getObjects: (id*)buffer inRange: (of_range_t)range { size_t i; for (i = 0; i < range.length; i++) buffer[i] = [self objectAtIndex: range.location + i]; } - (id*)objects { OFObject *container; size_t count; id *buffer; container = [[[OFObject alloc] init] autorelease]; count = [self count]; buffer = [container allocMemoryWithSize: sizeof(*buffer) count: [self count]]; [self getObjects: buffer inRange: of_range(0, count)]; return buffer; } - copy { return [self retain]; } - mutableCopy { return [[OFMutableArray alloc] initWithArray: self]; } - (id)objectAtIndex: (size_t)index { [self doesNotRecognizeSelector: _cmd]; abort(); } - (id)objectAtIndexedSubscript: (size_t)index { return [self objectAtIndex: index]; } - (size_t)indexOfObject: (id)object { size_t i, count; if (object == nil) return OF_NOT_FOUND; count = [self count]; for (i = 0; i < count; i++) if ([[self objectAtIndex: i] isEqual: object]) return i; return OF_NOT_FOUND; } - (size_t)indexOfObjectIdenticalTo: (id)object { size_t i, count; if (object == nil) return OF_NOT_FOUND; count = [self count]; for (i = 0; i < count; i++) if ([self objectAtIndex: i] == object) return i; return OF_NOT_FOUND; } - (bool)containsObject: (id)object { return ([self indexOfObject: object] != OF_NOT_FOUND); } - (bool)containsObjectIdenticalTo: (id)object { return ([self indexOfObjectIdenticalTo: object] != OF_NOT_FOUND); } - (id)firstObject { if ([self count] > 0) return [self objectAtIndex: 0]; return nil; } - (id)lastObject { size_t count = [self count]; if (count > 0) return [self objectAtIndex: count - 1]; return nil; } - (OFArray*)objectsInRange: (of_range_t)range { OFArray *ret; id *buffer; if (range.length > SIZE_MAX - range.location || range.location + range.length < [self count]) @throw [OFOutOfRangeException exception]; if (![self isKindOfClass: [OFMutableArray class]]) return [OFArray_subarray arrayWithArray: self range: range]; buffer = [self allocMemoryWithSize: sizeof(*buffer) count: range.length]; @try { [self getObjects: buffer inRange: range]; ret = [OFArray arrayWithObjects: buffer count: range.length]; } @finally { [self freeMemory: buffer]; } return ret; } - (OFString*)componentsJoinedByString: (OFString*)separator { return [self componentsJoinedByString: separator usingSelector: @selector(description)]; } - (OFString*)componentsJoinedByString: (OFString*)separator usingSelector: (SEL)selector { void *pool; OFMutableString *ret; id *objects; size_t i, count; IMP append; if (separator == nil) @throw [OFInvalidArgumentException exception]; count = [self count]; if (count == 0) return @""; if (count == 1) return [[self firstObject] performSelector: selector]; ret = [OFMutableString string]; append = [ret methodForSelector: @selector(appendString:)]; pool = objc_autoreleasePoolPush(); objects = [self objects]; for (i = 0; i < count - 1; i++) { void *pool2 = objc_autoreleasePoolPush(); append(ret, @selector(appendString:), [objects[i] performSelector: selector]); append(ret, @selector(appendString:), separator); objc_autoreleasePoolPop(pool2); } append(ret, @selector(appendString:), [objects[i] performSelector: selector]); [ret makeImmutable]; objc_autoreleasePoolPop(pool); return ret; } - (bool)isEqual: (id)object { /* FIXME: Optimize (for example, buffer of 16 for each) */ OFArray *otherArray; size_t i, count; if (![object isKindOfClass: [OFArray class]]) return false; otherArray = object; count = [self count]; if (count != [otherArray count]) return false; for (i = 0; i < count; i++) if (![[self objectAtIndex: i] isEqual: [otherArray objectAtIndex: i]]) return false; return true; } - (uint32_t)hash { id *objects = [self objects]; size_t i, count = [self count]; uint32_t hash; OF_HASH_INIT(hash); for (i = 0; i < count; i++) OF_HASH_ADD_HASH(hash, [objects[i] hash]); OF_HASH_FINALIZE(hash); return hash; } - (OFString*)description { void *pool; OFMutableString *ret; if ([self count] == 0) return @"()"; pool = objc_autoreleasePoolPush(); ret = [[self componentsJoinedByString: @",\n"] mutableCopy]; @try { [ret prependString: @"(\n"]; [ret replaceOccurrencesOfString: @"\n" withString: @"\n\t"]; [ret appendString: @"\n)"]; } @catch (id e) { [ret release]; @throw e; } objc_autoreleasePoolPop(pool); [ret makeImmutable]; return [ret autorelease]; } - (OFXMLElement*)XMLElementBySerializing { void *pool = objc_autoreleasePoolPush(); OFXMLElement *element; id <OFSerialization> *objects = [self objects]; size_t i, count = [self count]; if ([self isKindOfClass: [OFMutableArray class]]) element = [OFXMLElement elementWithName: @"OFMutableArray" namespace: OF_SERIALIZATION_NS]; else element = [OFXMLElement elementWithName: @"OFArray" namespace: OF_SERIALIZATION_NS]; for (i = 0; i < count; i++) { void *pool2 = objc_autoreleasePoolPush(); [element addChild: [objects[i] XMLElementBySerializing]]; objc_autoreleasePoolPop(pool2); } [element retain]; objc_autoreleasePoolPop(pool); return [element autorelease]; } - (OFString*)JSONRepresentation { void *pool = objc_autoreleasePoolPush(); OFMutableString *JSON; JSON = [[self componentsJoinedByString: @"," usingSelector: @selector(JSONRepresentation)] mutableCopy]; [JSON prependString: @"["]; [JSON appendString: @"]"]; [JSON makeImmutable]; objc_autoreleasePoolPop(pool); return [JSON autorelease]; } - (OFDataArray*)messagePackRepresentation { OFDataArray *data; size_t i, count; void *pool; OFEnumerator *enumerator; id object; data = [OFDataArray dataArray]; count = [self count]; if (count <= 15) { uint8_t tmp = 0x90 | ((uint8_t)count & 0xF); [data addItem: &tmp]; } else if (count <= UINT16_MAX) { uint8_t type = 0xDC; uint16_t tmp = OF_BSWAP16_IF_LE((uint16_t)count); [data addItem: &type]; [data addItems: &tmp count: sizeof(tmp)]; } else if (count <= UINT32_MAX) { uint8_t type = 0xDC; uint32_t tmp = OF_BSWAP32_IF_LE((uint32_t)count); [data addItem: &type]; [data addItems: &tmp count: sizeof(tmp)]; } else @throw [OFOutOfRangeException exception]; pool = objc_autoreleasePoolPush(); i = 0; enumerator = [self objectEnumerator]; while ((object = [enumerator nextObject]) != nil) { void *pool2 = objc_autoreleasePoolPush(); OFDataArray *child; i++; child = [object messagePackRepresentation]; [data addItems: [child items] count: [child count]]; objc_autoreleasePoolPop(pool2); } assert(i == count); objc_autoreleasePoolPop(pool); return data; } - (void)makeObjectsPerformSelector: (SEL)selector { id *objects = [self objects]; size_t i, count = [self count]; for (i = 0; i < count; i++) ((void(*)(id, SEL))[objects[i] methodForSelector: selector])(objects[i], selector); } - (void)makeObjectsPerformSelector: (SEL)selector withObject: (id)object { id *objects = [self objects]; size_t i, count = [self count]; for (i = 0; i < count; i++) ((void(*)(id, SEL, id))[objects[i] methodForSelector: selector])(objects[i], selector, object); } - (OFArray*)sortedArray { OFMutableArray *new = [[self mutableCopy] autorelease]; [new sort]; [new makeImmutable]; return new; } - (OFArray*)sortedArrayWithOptions: (int)options { OFMutableArray *new = [[self mutableCopy] autorelease]; [new sortWithOptions: options]; [new makeImmutable]; return new; } - (OFArray*)reversedArray { OFMutableArray *new = [[self mutableCopy] autorelease]; [new reverse]; [new makeImmutable]; return new; } - (int)countByEnumeratingWithState: (of_fast_enumeration_state_t*)state objects: (id*)objects count: (int)count { of_range_t range = of_range(state->state, count); if (range.length > SIZE_MAX - range.location) @throw [OFOutOfRangeException exception]; if (range.location + range.length > [self count]) range.length = [self count] - range.location; [self getObjects: objects inRange: range]; state->state = range.location + range.length; state->itemsPtr = objects; state->mutationsPtr = (unsigned long*)self; return (int)range.length; } - (OFEnumerator*)objectEnumerator { return [[[OFArrayEnumerator alloc] initWithArray: self mutationsPtr: NULL] autorelease]; } #if defined(OF_HAVE_BLOCKS) && defined(OF_HAVE_FAST_ENUMERATION) - (void)enumerateObjectsUsingBlock: (of_array_enumeration_block_t)block { size_t i = 0; bool stop = false; for (id object in self) { block(object, i++, &stop); if (stop) break; } } #endif - (OFArray*)arrayByAddingObject: (id)object { OFMutableArray *ret; if (object == nil) @throw [OFInvalidArgumentException exception]; ret = [[self mutableCopy] autorelease]; [ret addObject: object]; [ret makeImmutable]; return ret; } - (OFArray*)arrayByAddingObjectsFromArray: (OFArray*)array { OFMutableArray *ret = [[self mutableCopy] autorelease]; [ret addObjectsFromArray: array]; [ret makeImmutable]; return ret; } - (OFArray*)arrayByRemovingObject: (id)object { OFMutableArray *ret = [[self mutableCopy] autorelease]; [ret removeObject: object]; [ret makeImmutable]; return ret; } #ifdef OF_HAVE_BLOCKS - (OFArray*)mappedArrayUsingBlock: (of_array_map_block_t)block { OFArray *ret; size_t count = [self count]; id *tmp = [self allocMemoryWithSize: sizeof(id) count: count]; @try { [self enumerateObjectsUsingBlock: ^ (id object, size_t index, bool *stop) { tmp[index] = block(object, index); }]; ret = [OFArray arrayWithObjects: tmp count: count]; } @finally { [self freeMemory: tmp]; } return ret; } - (OFArray*)filteredArrayUsingBlock: (of_array_filter_block_t)block { OFArray *ret; size_t count = [self count]; id *tmp = [self allocMemoryWithSize: sizeof(id) count: count]; @try { __block size_t i = 0; [self enumerateObjectsUsingBlock: ^ (id object, size_t index, bool *stop) { if (block(object, index)) tmp[i++] = object; }]; ret = [OFArray arrayWithObjects: tmp count: i]; } @finally { [self freeMemory: tmp]; } return ret; } - (id)foldUsingBlock: (of_array_fold_block_t)block { size_t count = [self count]; __block id current; if (count == 0) return nil; if (count == 1) return [[[self firstObject] retain] autorelease]; [self enumerateObjectsUsingBlock: ^ (id object, size_t index, bool *stop) { id new; if (index == 0) { current = [object retain]; return; } @try { new = [block(current, object) retain]; } @finally { [current release]; } current = new; }]; return [current autorelease]; } #endif @end @implementation OFArrayEnumerator - initWithArray: (OFArray*)array_ mutationsPtr: (unsigned long*)mutationsPtr_ { self = [super init]; array = [array_ retain]; count = [array count]; mutations = (mutationsPtr_ != NULL ? *mutationsPtr_ : 0); mutationsPtr = mutationsPtr_; return self; } - (void)dealloc { [array release]; [super dealloc]; } - (id)nextObject { if (mutationsPtr != NULL && *mutationsPtr != mutations) @throw [OFEnumerationMutationException exceptionWithObject: array]; if (position < count) return [array objectAtIndex: position++]; return nil; } - (void)reset { if (mutationsPtr != NULL && *mutationsPtr != mutations) @throw [OFEnumerationMutationException exceptionWithObject: array]; position = 0; } @end