Artifact 3d57d1e63c30563b0dcce79b845f25b9fd98f0be6ad94ed53575ceba852f3e50:
- File
src/OFAdjacentArray.m
— part of check-in
[6ce0093f8d]
at
2023-04-10 19:22:32
on branch trunk
— Remove OFSerialization
While the idea sounds nice that the tag name is the class, this means the
serialization includes whether something is mutable or immutable. This means
doing as much as making something immutable changes the serialization, which
can then cause issues after being deserialized. (user: js, size: 6247) [annotate] [blame] [check-ins using] [more...]
/* * Copyright (c) 2008-2023 Jonathan Schleifer <js@nil.im> * * 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> #import "OFAdjacentArray.h" #import "OFAdjacentSubarray.h" #import "OFData.h" #import "OFMutableAdjacentArray.h" #import "OFString.h" #import "OFEnumerationMutationException.h" #import "OFInvalidArgumentException.h" #import "OFOutOfRangeException.h" @implementation OFAdjacentArray - (instancetype)init { self = [super init]; @try { _array = [[OFMutableData alloc] initWithItemSize: sizeof(id)]; } @catch (id e) { [self release]; @throw e; } return self; } - (instancetype)initWithObject: (id)object { self = [self init]; @try { if (object == nil) @throw [OFInvalidArgumentException exception]; [_array addItem: &object]; [object retain]; } @catch (id e) { [self release]; @throw e; } return self; } - (instancetype)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; } - (instancetype)initWithArray: (OFArray *)array { id const *objects; size_t count; self = [super init]; if (array == nil) return self; @try { objects = array.objects; count = array.count; _array = [[OFMutableData alloc] initWithItemSize: sizeof(id) capacity: count]; } @catch (id e) { [self release]; @throw e; } @try { for (size_t i = 0; i < count; i++) [objects[i] retain]; [_array addItems: objects count: count]; } @catch (id e) { for (size_t i = 0; i < count; i++) [objects[i] release]; /* Prevent double-release of objects */ [_array release]; _array = nil; [self release]; @throw e; } return self; } - (instancetype)initWithObjects: (id const *)objects count: (size_t)count { self = [self init]; @try { bool ok = true; for (size_t i = 0; i < count; i++) { if (objects[i] == nil) ok = false; [objects[i] retain]; } if (!ok) @throw [OFInvalidArgumentException exception]; [_array addItems: objects count: count]; } @catch (id e) { for (size_t i = 0; i < count; i++) [objects[i] release]; [self release]; @throw e; } return self; } - (size_t)count { return _array.count; } - (id const *)objects { return _array.items; } - (id)objectAtIndex: (size_t)idx { return *((id *)[_array itemAtIndex: idx]); } - (id)objectAtIndexedSubscript: (size_t)idx { return *((id *)[_array itemAtIndex: idx]); } - (void)getObjects: (id *)buffer inRange: (OFRange)range { id const *objects = _array.items; size_t count = _array.count; if (range.length > SIZE_MAX - range.location || range.location + range.length > count) @throw [OFOutOfRangeException exception]; for (size_t i = 0; i < range.length; i++) buffer[i] = objects[range.location + i]; } - (size_t)indexOfObject: (id)object { id const *objects; size_t count; if (object == nil) return OFNotFound; objects = _array.items; count = _array.count; for (size_t i = 0; i < count; i++) if ([objects[i] isEqual: object]) return i; return OFNotFound; } - (size_t)indexOfObjectIdenticalTo: (id)object { id const *objects; size_t count; if (object == nil) return OFNotFound; objects = _array.items; count = _array.count; for (size_t i = 0; i < count; i++) if (objects[i] == object) return i; return OFNotFound; } - (OFArray *)objectsInRange: (OFRange)range { if (range.length > SIZE_MAX - range.location || range.location + range.length > _array.count) @throw [OFOutOfRangeException exception]; if ([self isKindOfClass: [OFMutableArray class]]) return [OFArray arrayWithObjects: (id *)_array.items + range.location count: range.length]; return [OFAdjacentSubarray arrayWithArray: self range: range]; } - (bool)isEqual: (id)object { OFArray *otherArray; id const *objects, *otherObjects; size_t count; if (object == self) return true; if (![object isKindOfClass: [OFAdjacentArray class]] && ![object isKindOfClass: [OFMutableAdjacentArray class]]) return [super isEqual: object]; otherArray = object; count = _array.count; if (count != otherArray.count) return false; objects = _array.items; otherObjects = otherArray.objects; for (size_t i = 0; i < count; i++) if (![objects[i] isEqual: otherObjects[i]]) return false; return true; } - (unsigned long)hash { id const *objects = _array.items; size_t count = _array.count; unsigned long hash; OFHashInit(&hash); for (size_t i = 0; i < count; i++) OFHashAddHash(&hash, [objects[i] hash]); OFHashFinalize(&hash); return hash; } - (int)countByEnumeratingWithState: (OFFastEnumerationState *)state objects: (id *)objects count: (int)count_ { size_t count = _array.count; if (count > INT_MAX) /* * Use the implementation from OFArray, which is slower, but can * enumerate in chunks. */ return [super countByEnumeratingWithState: state objects: objects count: count_]; if (state->state >= count) return 0; state->state = (unsigned long)count; state->itemsPtr = (id *)_array.items; state->mutationsPtr = (unsigned long *)self; return (int)count; } #ifdef OF_HAVE_BLOCKS - (void)enumerateObjectsUsingBlock: (OFArrayEnumerationBlock)block { id const *objects = _array.items; size_t count = _array.count; bool stop = false; for (size_t i = 0; i < count && !stop; i++) block(objects[i], i, &stop); } #endif - (void)dealloc { id const *objects = _array.items; size_t count = _array.count; for (size_t i = 0; i < count; i++) [objects[i] release]; [_array release]; [super dealloc]; } @end