Skip to content

Instantly share code, notes, and snippets.

@mmackh
Last active August 29, 2015 13:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mmackh/8780862 to your computer and use it in GitHub Desktop.
Save mmackh/8780862 to your computer and use it in GitHub Desktop.
Ordered NSCountedSet. Subclassing and overwrite `- (id)keyForObject:(id)object` to specify your own keys for objects.
//
// PCCountedObjectContainer.h
// Slingshot
//
// Created by Maximilian Mackh on 02/02/14.
// Copyright (c) 2014 Professional Consulting & Trading GmbH. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface PCCountedObjectContainer : NSObject
- (instancetype)initWithContainer:(PCCountedObjectContainer *)container;
- (void)addObject:(id)object;
- (void)insertObject:(id)object atIndex:(NSInteger)index;
- (void)removeObject:(id)object;
- (void)addAllObjectsFromContainer:(PCCountedObjectContainer *)container;
- (void)removeAllObjectsFromContainer:(PCCountedObjectContainer *)container;
- (NSInteger)countForObject:(id)object;
- (NSArray *)allObjects;
- (NSInteger)count;
@end
//
// PCCountedObjectContainer.m
// Slingshot
//
// Created by Maximilian Mackh on 02/02/14.
// Copyright (c) 2014 Professional Consulting & Trading GmbH. All rights reserved.
//
#import "PCCountedObjectContainer.h"
typedef NS_ENUM(NSInteger, PCCountedObjectMethod)
{
PCCountedObjectMethodAdd,
PCCountedObjectMethodRemove
};
@implementation PCCountedObjectContainer
{
NSMutableDictionary *_objectCounter;
NSMutableArray *_objects;
}
- (instancetype)init
{
self = [super init];
if (!self) return nil;
_objectCounter = [NSMutableDictionary new];
_objects = [NSMutableArray new];
return self;
}
- (instancetype)initWithContainer:(PCCountedObjectContainer *)container
{
self = [self init];
if (!self) return nil;
NSInteger index = 0;
for (id object in container.allObjects)
{
NSInteger cycles = [container countForObject:object];
while (cycles --> 0)
{
id targetObject = [container.allObjects objectAtIndex:index];
[self addObject:targetObject];
}
index++;
}
return self;
}
- (void)addObject:(id)object
{
[self modifyMappingForObject:object method:PCCountedObjectMethodAdd index:NSNotFound];
}
- (void)addAllObjectsFromContainer:(PCCountedObjectContainer *)container
{
for (id object in [container allObjects])
{
NSInteger cycles = [container countForObject:object];
while (cycles --> 0)
{
[self addObject:object];
}
}
}
- (void)removeAllObjectsFromContainer:(PCCountedObjectContainer *)container
{
for (id object in [container allObjects])
{
NSInteger cycles = [container countForObject:object];
while (cycles --> 0)
{
[self removeObject:object];
}
}
}
- (void)insertObject:(id)object atIndex:(NSInteger)index
{
[self modifyMappingForObject:object method:PCCountedObjectMethodAdd index:index];
}
- (void)removeObject:(id)object
{
[self modifyMappingForObject:object method:PCCountedObjectMethodRemove index:NSNotFound];
}
- (void)modifyMappingForObject:(id)object method:(PCCountedObjectMethod)method index:(NSInteger)index
{
id key = [self keyForObject:object];
if (_objectCounter[key])
{
NSInteger counter = [_objectCounter[key] integerValue];
counter = (method == PCCountedObjectMethodAdd) ? (counter + 1) : (counter - 1);
_objectCounter[key] = @(counter);
}
if (method == PCCountedObjectMethodAdd && !_objectCounter[key])
{
_objectCounter[key] = @(1);
if (index == NSNotFound)
{
[_objects addObject:object];
}
else
{
[_objects insertObject:object atIndex:index];
}
return;
}
if (method == PCCountedObjectMethodAdd && _objectCounter[key])
{
if (index != NSNotFound)
{
[_objects removeObject:object];
[_objects insertObject:object atIndex:index];
}
}
if (method == PCCountedObjectMethodRemove && ![_objectCounter[key] integerValue])
{
[_objectCounter removeObjectForKey:key];
[_objects removeObject:object];
}
}
- (NSInteger)countForObject:(id)object
{
id key = [self keyForObject:object];
if (_objectCounter[key])
{
return [_objectCounter[key] integerValue];
}
return 0;
}
- (NSArray *)allObjects
{
return _objects;
}
- (NSInteger)count
{
return _objects.count;
}
- (id)keyForObject:(id)object
{
return @([object hash]).stringValue;
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment