Artifact a5c8b76a0dde84a51cf4ed0bb1642601405626ad9b181f64bfa4db26189229a0:
- File
src/OFSet.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: 7145) [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 <stdlib.h> #import "OFSet.h" #import "OFArray.h" #import "OFMapTableSet.h" #import "OFNull.h" #import "OFString.h" static struct { Class isa; } placeholder; @interface OFSetPlaceholder: OFSet @end @implementation OFSetPlaceholder - (instancetype)init { return (id)[[OFMapTableSet alloc] init]; } - (instancetype)initWithSet: (OFSet *)set { return (id)[[OFMapTableSet alloc] initWithSet: set]; } - (instancetype)initWithArray: (OFArray *)array { return (id)[[OFMapTableSet alloc] initWithArray: array]; } - (instancetype)initWithObjects: (id)firstObject, ... { id ret; va_list arguments; va_start(arguments, firstObject); ret = [[OFMapTableSet alloc] initWithObject: firstObject arguments: arguments]; va_end(arguments); return ret; } - (instancetype)initWithObjects: (id const *)objects count: (size_t)count { return (id)[[OFMapTableSet alloc] initWithObjects: objects count: count]; } - (instancetype)initWithObject: (id)firstObject arguments: (va_list)arguments { return (id)[[OFMapTableSet alloc] initWithObject: firstObject arguments: arguments]; } - (instancetype)retain { return self; } - (instancetype)autorelease { return self; } - (void)release { } - (void)dealloc { OF_DEALLOC_UNSUPPORTED } @end @implementation OFSet + (void)initialize { if (self == [OFSet class]) placeholder.isa = [OFSetPlaceholder class]; } + (instancetype)alloc { if (self == [OFSet class]) return (id)&placeholder; return [super alloc]; } + (instancetype)set { return [[[self alloc] init] autorelease]; } + (instancetype)setWithSet: (OFSet *)set { return [[[self alloc] initWithSet: set] autorelease]; } + (instancetype)setWithArray: (OFArray *)array { return [[[self alloc] initWithArray: array] autorelease]; } + (instancetype)setWithObjects: (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)setWithObjects: (id const *)objects count: (size_t)count { return [[[self alloc] initWithObjects: objects count: count] autorelease]; } - (instancetype)init { if ([self isMemberOfClass: [OFSet class]]) { @try { [self doesNotRecognizeSelector: _cmd]; } @catch (id e) { [self release]; @throw e; } abort(); } return [super init]; } - (instancetype)initWithSet: (OFSet *)set { OF_INVALID_INIT_METHOD } - (instancetype)initWithArray: (OFArray *)array { OF_INVALID_INIT_METHOD } - (instancetype)initWithObjects: (id const *)objects count: (size_t)count { OF_INVALID_INIT_METHOD } - (instancetype)initWithObjects: (id)firstObject, ... { id ret; va_list arguments; va_start(arguments, firstObject); ret = [self initWithObject: firstObject arguments: arguments]; va_end(arguments); return ret; } - (instancetype)initWithObject: (id)firstObject arguments: (va_list)arguments { OF_INVALID_INIT_METHOD } - (size_t)count { OF_UNRECOGNIZED_SELECTOR } - (id)valueForKey: (OFString *)key { id ret; if ([key isEqual: @"@count"]) return [super valueForKey: @"count"]; ret = [OFMutableSet setWithCapacity: self.count]; for (id object in self) { id value = [object valueForKey: key]; if (value != nil) [ret addObject: value]; } [ret makeImmutable]; return ret; } - (void)setValue: (id)value forKey: (OFString *)key { for (id object in self) [object setValue: value forKey: key]; } - (bool)containsObject: (id)object { OF_UNRECOGNIZED_SELECTOR } - (OFEnumerator *)objectEnumerator { OF_UNRECOGNIZED_SELECTOR } - (int)countByEnumeratingWithState: (OFFastEnumerationState *)state objects: (id *)objects count: (int)count { OFEnumerator *enumerator; int i; memcpy(&enumerator, state->extra, sizeof(enumerator)); if (enumerator == nil) { enumerator = [self objectEnumerator]; memcpy(state->extra, &enumerator, sizeof(enumerator)); } state->itemsPtr = objects; state->mutationsPtr = (unsigned long *)self; for (i = 0; i < count; i++) { id object = [enumerator nextObject]; if (object == nil) return i; objects[i] = object; } return i; } - (bool)isEqual: (id)object { OFSet *set; if (object == self) return true; if (![object isKindOfClass: [OFSet class]]) return false; set = object; if (set.count != self.count) return false; return [set isSubsetOfSet: self]; } - (unsigned long)hash { void *pool = objc_autoreleasePoolPush(); unsigned long hash = 0; for (id object in self) hash ^= [object hash]; objc_autoreleasePoolPop(pool); return hash; } - (OFString *)description { void *pool; OFMutableString *ret; size_t i, count = self.count; if (count == 0) return @"{()}"; ret = [OFMutableString stringWithString: @"{(\n"]; pool = objc_autoreleasePoolPush(); i = 0; for (id object in self) { void *pool2 = objc_autoreleasePoolPush(); [ret appendString: [object description]]; if (++i < count) [ret appendString: @",\n"]; objc_autoreleasePoolPop(pool2); } [ret replaceOccurrencesOfString: @"\n" withString: @"\n\t"]; [ret appendString: @"\n)}"]; [ret makeImmutable]; objc_autoreleasePoolPop(pool); return ret; } - (id)copy { return [self retain]; } - (id)mutableCopy { return [[OFMutableSet alloc] initWithSet: self]; } - (bool)isSubsetOfSet: (OFSet *)set { for (id object in self) if (![set containsObject: object]) return false; return true; } - (bool)intersectsSet: (OFSet *)set { for (id object in self) if ([set containsObject: object]) return true; return false; } - (OFSet *)setByAddingObjectsFromSet: (OFSet *)set { OFMutableSet *new = [[self mutableCopy] autorelease]; [new unionSet: set]; [new makeImmutable]; return new; } - (OFArray *)allObjects { void *pool = objc_autoreleasePoolPush(); OFArray *ret = [[[self objectEnumerator] allObjects] retain]; objc_autoreleasePoolPop(pool); return [ret autorelease]; } - (id)anyObject { void *pool = objc_autoreleasePoolPush(); id ret = [[[self objectEnumerator] nextObject] retain]; objc_autoreleasePoolPop(pool); return [ret autorelease]; } #ifdef OF_HAVE_BLOCKS - (void)enumerateObjectsUsingBlock: (OFSetEnumerationBlock)block { bool stop = false; for (id object in self) { block(object, &stop); if (stop) break; } } - (OFSet *)filteredSetUsingBlock: (OFSetFilterBlock)block { OFMutableSet *ret = [OFMutableSet set]; [self enumerateObjectsUsingBlock: ^ (id object, bool *stop) { if (block(object)) [ret addObject: object]; }]; [ret makeImmutable]; return ret; } #endif @end