Artifact 2550c38e591a48b3012c597fda102f411769e1b0d6d2e7dd2fa2f14288a809a0:
- File
src/OFCountedSet.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: 4628) [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 "OFCountedSet.h" #import "OFCountedMapTableSet.h" #import "OFNumber.h" #import "OFString.h" static struct { Class isa; } placeholder; @interface OFCountedSetPlaceholder: OFCountedSet @end @implementation OFCountedSetPlaceholder - (instancetype)init { return (id)[[OFCountedMapTableSet alloc] init]; } - (instancetype)initWithSet: (OFSet *)set { return (id)[[OFCountedMapTableSet alloc] initWithSet: set]; } - (instancetype)initWithArray: (OFArray *)array { return (id)[[OFCountedMapTableSet alloc] initWithArray: array]; } - (instancetype)initWithObjects: (id)firstObject, ... { id ret; va_list arguments; va_start(arguments, firstObject); ret = [[OFCountedMapTableSet alloc] initWithObject: firstObject arguments: arguments]; va_end(arguments); return ret; } - (instancetype)initWithObjects: (id const *)objects count: (size_t)count { return (id)[[OFCountedMapTableSet alloc] initWithObjects: objects count: count]; } - (instancetype)initWithObject: (id)firstObject arguments: (va_list)arguments { return (id)[[OFCountedMapTableSet alloc] initWithObject: firstObject arguments: arguments]; } - (instancetype)retain { return self; } - (instancetype)autorelease { return self; } - (void)release { } - (void)dealloc { OF_DEALLOC_UNSUPPORTED } @end @implementation OFCountedSet + (void)initialize { if (self == [OFCountedSet class]) placeholder.isa = [OFCountedSetPlaceholder class]; } + (instancetype)alloc { if (self == [OFCountedSet class]) return (id)&placeholder; return [super alloc]; } - (instancetype)init { if ([self isMemberOfClass: [OFCountedSet class]]) { @try { [self doesNotRecognizeSelector: _cmd]; } @catch (id e) { [self release]; @throw e; } abort(); } return [super init]; } - (size_t)countForObject: (id)object { OF_UNRECOGNIZED_SELECTOR } - (OFString *)description { OFMutableString *ret; void *pool; 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]; [ret appendFormat: @": %zu", [self countForObject: object]]; 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 [[OFCountedSet alloc] initWithSet: self]; } - (id)mutableCopy { return [[OFCountedSet alloc] initWithSet: self]; } #ifdef OF_HAVE_BLOCKS - (void)enumerateObjectsAndCountUsingBlock: (OFCountedSetEnumerationBlock)block { [self enumerateObjectsUsingBlock: ^ (id object, bool *stop) { block(object, [self countForObject: object], stop); }]; } #endif - (void)minusSet: (OFSet *)set { void *pool = objc_autoreleasePoolPush(); if ([set isKindOfClass: [OFCountedSet class]]) { OFCountedSet *countedSet = (OFCountedSet *)set; for (id object in countedSet) { size_t count = [countedSet countForObject: object]; for (size_t i = 0; i < count; i++) [self removeObject: object]; } } else for (id object in set) [self removeObject: object]; objc_autoreleasePoolPop(pool); } - (void)unionSet: (OFSet *)set { void *pool = objc_autoreleasePoolPush(); if ([set isKindOfClass: [OFCountedSet class]]) { OFCountedSet *countedSet = (OFCountedSet *)set; for (id object in countedSet) { size_t count = [countedSet countForObject: object]; for (size_t i = 0; i < count; i++) [self addObject: object]; } } else for (id object in set) [self addObject: object]; objc_autoreleasePoolPop(pool); } - (void)removeAllObjects { void *pool = objc_autoreleasePoolPush(); OFSet *copy = [[self copy] autorelease]; for (id object in copy) { size_t count = [self countForObject: object]; for (size_t i = 0; i < count; i++) [self removeObject: object]; } objc_autoreleasePoolPop(pool); } @end