/* * Copyright (c) 2008, 2009, 2010, 2011 * 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 <string.h> #import "OFMutableArray.h" #import "OFDataArray.h" #import "OFAutoreleasePool.h" #import "OFEnumerationMutationException.h" #import "OFInvalidArgumentException.h" #import "OFOutOfRangeException.h" @implementation OFMutableArray - copy { OFArray *new = [[OFArray alloc] init]; id *objs; size_t count, i; objs = [array cArray]; count = [array count]; [new->array addNItems: count fromCArray: objs]; for (i = 0; i < count; i++) [objs[i] retain]; return new; } - (void)addObject: (id)obj { [array addItem: &obj]; [obj retain]; mutations++; } - (void)addObject: (id)obj atIndex: (size_t)index { [array addItem: &obj atIndex: index]; [obj retain]; mutations++; } - (void)replaceObject: (id)old withObject: (id)new { id *objs = [array cArray]; size_t i, count = [array count]; for (i = 0; i < count; i++) { if ([objs[i] isEqual: old]) { [new retain]; [objs[i] release]; objs[i] = new; return; } } } - (void)replaceObjectAtIndex: (size_t)index withObject: (id)obj { id *objs = [array cArray]; id old; if (index >= [array count]) @throw [OFOutOfRangeException newWithClass: isa]; old = objs[index]; objs[index] = [obj retain]; [old release]; } - (void)replaceObjectIdenticalTo: (id)old withObject: (id)new { id *objs = [array cArray]; size_t i, count = [array count]; for (i = 0; i < count; i++) { if (objs[i] == old) { [new retain]; [objs[i] release]; objs[i] = new; return; } } } - (void)removeObject: (id)obj { id *objs = [array cArray]; size_t i, count = [array count]; for (i = 0; i < count; i++) { if ([objs[i] isEqual: obj]) { id obj = objs[i]; [array removeItemAtIndex: i]; mutations++; [obj release]; return; } } } - (void)removeObjectIdenticalTo: (id)obj { id *objs = [array cArray]; size_t i, count = [array count]; for (i = 0; i < count; i++) { if (objs[i] == obj) { [array removeItemAtIndex: i]; mutations++; [obj release]; return; } } } - (void)removeObjectAtIndex: (size_t)index { id old = [self objectAtIndex: index]; [array removeItemAtIndex: index]; [old release]; mutations++; } - (void)removeNObjects: (size_t)nobjects { id *objs = [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, objs + (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 *objs = [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, objs + index, nobjects * sizeof(id)); @try { [array removeNItems: nobjects atIndex: index]; mutations++; for (i = 0; i < nobjects; i++) [copy[i] release]; } @finally { [self freeMemory: copy]; } } - (int)countByEnumeratingWithState: (of_fast_enumeration_state_t*)state objects: (id*)objects count: (int)count_ { size_t count = [array count]; if (count > INT_MAX) @throw [OFOutOfRangeException newWithClass: isa]; if (state->state >= count) return 0; state->state = count; state->itemsPtr = [array cArray]; state->mutationsPtr = &mutations; return (int)count; } - (OFEnumerator*)objectEnumerator { return [[[OFArrayEnumerator alloc] initWithArray: self dataArray: array mutationsPointer: &mutations] autorelease]; } #ifdef OF_HAVE_BLOCKS - (void)enumerateObjectsUsingBlock: (of_array_enumeration_block_t)block { OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; id *objs = [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(objs[i], i, &stop); [pool releaseObjects]; } [pool release]; } - (void)replaceObjectsUsingBlock: (of_array_replace_block_t)block { OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; id *objs = [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]; id new = block(objs[i], i, &stop); if (new == nil) @throw [OFInvalidArgumentException newWithClass: isa selector: _cmd]; [new retain]; [objs[i] release]; objs[i] = new; [pool releaseObjects]; } [pool release]; } #endif @end