/*
* Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
*
* All rights reserved.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License version 3.0 only,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* version 3.0 for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* version 3.0 along with this program. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <stdlib.h>
#import "OFConcreteMutableDictionary.h"
#import "OFArray.h"
#import "OFString.h"
static struct {
Class isa;
} placeholder;
@interface OFPlaceholderMutableDictionary: OFDictionary
@end
@implementation OFPlaceholderMutableDictionary
- (instancetype)init
{
return (id)[[OFConcreteMutableDictionary alloc] init];
}
- (instancetype)initWithDictionary: (OFDictionary *)dictionary
{
return (id)[[OFConcreteMutableDictionary alloc]
initWithDictionary: dictionary];
}
- (instancetype)initWithObject: (id)object forKey: (id)key
{
return (id)[[OFConcreteMutableDictionary alloc] initWithObject: object
forKey: key];
}
- (instancetype)initWithObjects: (OFArray *)objects forKeys: (OFArray *)keys
{
return (id)[[OFConcreteMutableDictionary alloc] initWithObjects: objects
forKeys: keys];
}
- (instancetype)initWithObjects: (id const *)objects
forKeys: (id const *)keys
count: (size_t)count
{
return (id)[[OFConcreteMutableDictionary alloc] initWithObjects: objects
forKeys: keys
count: count];
}
- (instancetype)initWithKeysAndObjects: (id)firstKey, ...
{
id ret;
va_list arguments;
va_start(arguments, firstKey);
ret = (id)[[OFConcreteMutableDictionary alloc] initWithKey: firstKey
arguments: arguments];
va_end(arguments);
return ret;
}
- (instancetype)initWithKey: (id)firstKey arguments: (va_list)arguments
{
return (id)[[OFConcreteMutableDictionary alloc] initWithKey: firstKey
arguments: arguments];
}
- (instancetype)initWithCapacity: (size_t)capacity
{
return (id)[[OFConcreteMutableDictionary alloc]
initWithCapacity: capacity];
}
OF_SINGLETON_METHODS
@end
@implementation OFMutableDictionary
+ (void)initialize
{
if (self == [OFMutableDictionary class])
object_setClass((id)&placeholder,
[OFPlaceholderMutableDictionary class]);
}
+ (instancetype)alloc
{
if (self == [OFMutableDictionary class])
return (id)&placeholder;
return [super alloc];
}
+ (instancetype)dictionaryWithCapacity: (size_t)capacity
{
return [[[self alloc] initWithCapacity: capacity] autorelease];
}
- (instancetype)init
{
return [super init];
}
#ifdef __clang__
/* We intentionally don't call into super, so silence the warning. */
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wunknown-pragmas"
# pragma clang diagnostic ignored "-Wobjc-designated-initializers"
#endif
- (instancetype)initWithObjects: (id const *)objects
forKeys: (id const *)keys
count: (size_t)count
{
OF_INVALID_INIT_METHOD
}
- (instancetype)initWithCapacity: (size_t)capacity
{
OF_INVALID_INIT_METHOD
}
#ifdef __clang__
# pragma clang diagnostic pop
#endif
- (void)setObject: (id)object forKey: (id)key
{
OF_UNRECOGNIZED_SELECTOR
}
- (void)setObject: (id)object forKeyedSubscript: (id)key
{
if (object != nil)
[self setObject: object forKey: key];
else
[self removeObjectForKey: key];
}
- (void)removeObjectForKey: (id)key
{
OF_UNRECOGNIZED_SELECTOR
}
- (void)removeAllObjects
{
void *pool = objc_autoreleasePoolPush();
for (id key in self.allKeys)
[self removeObjectForKey: key];
objc_autoreleasePoolPop(pool);
}
- (id)copy
{
return [[OFDictionary alloc] initWithDictionary: self];
}
- (void)addEntriesFromDictionary: (OFDictionary *)dictionary
{
void *pool = objc_autoreleasePoolPush();
OFEnumerator *keyEnumerator = [dictionary keyEnumerator];
OFEnumerator *objectEnumerator = [dictionary objectEnumerator];
id key, object;
while ((key = [keyEnumerator nextObject]) != nil &&
(object = [objectEnumerator nextObject]) != nil)
[self setObject: object forKey: key];
objc_autoreleasePoolPop(pool);
}
#ifdef OF_HAVE_BLOCKS
- (void)replaceObjectsUsingBlock: (OFDictionaryReplaceBlock)block
{
[self enumerateKeysAndObjectsUsingBlock: ^ (id key, id object,
bool *stop) {
id new = block(key, object);
if (new != object) {
[self setObject: block(key, object) forKey: key];
}
}];
}
#endif
- (void)makeImmutable
{
}
@end