Skip to content

Instantly share code, notes, and snippets.

@werediver
Created August 22, 2014 11:45
Show Gist options
  • Save werediver/5345f91c897b8173e40e to your computer and use it in GitHub Desktop.
Save werediver/5345f91c897b8173e40e to your computer and use it in GitHub Desktop.
Simple implementation of circular queue in Objective-C (for ARC-enabled environment).
//
// CircularQueue.h
//
// Created on 9/21/13.
//
#import <Foundation/Foundation.h>
@interface CircularQueue : NSObject <NSFastEnumeration>
@property (nonatomic, assign, readonly) NSUInteger capacity;
@property (nonatomic, assign, readonly) NSUInteger count;
- (id)initWithCapacity:(NSUInteger)capacity;
- (void)enqObject:(id)obj; // Enqueue
- (id)deqObject; // Dequeue
- (id)objectAtIndex:(NSUInteger)index;
- (void)removeAllObjects;
@end
//
// CircularQueue.m
//
// Created on 9/21/13.
//
#import "CircularQueue.h"
@interface CircularQueue () {
NSMutableArray *_array;
NSUInteger _start;
unsigned long _mutationCounter;
}
@end
@implementation CircularQueue
- (id)initWithCapacity:(NSUInteger)capacity {
self = [super init];
if (self) {
_capacity = capacity;
_array = [[NSMutableArray alloc] initWithCapacity:_capacity];
for (NSUInteger i = 0; i < _capacity; ++i) {
[_array addObject:[NSNull null]];
}
}
return self;
}
- (void)enqObject:(id)obj {
const NSUInteger next = (_start + _count) % _capacity;
[_array replaceObjectAtIndex:next withObject:obj];
if (_count == _capacity) {
// The queue was already full and the head is overwriten.
_start = (_start + 1) % _capacity;
} else {
_count += 1;
}
_mutationCounter += 1;
}
- (id)deqObject {
if (_count < 1)
@throw [[NSException alloc] initWithName:NSRangeException reason:nil userInfo:nil];
const id obj = [_array objectAtIndex:_start];
[_array replaceObjectAtIndex:_start withObject:[NSNull null]];
_start = (_start + 1) % _capacity;
_count -= 1;
_mutationCounter += 1;
return obj;
}
- (id)objectAtIndex:(NSUInteger)index {
if (index >= _capacity)
@throw [[NSException alloc] initWithName:NSRangeException reason:nil userInfo:nil];
return [_array objectAtIndex:(_start + index) % _capacity];
}
- (void)removeAllObjects {
for (NSUInteger i = 0; i < _capacity; ++i) {
[_array replaceObjectAtIndex:i withObject:[NSNull null]];
}
_start = _count = 0;
_mutationCounter += 1;
}
- (NSString *)description {
const BOOL multiline = (_count > 1);
NSMutableString *const description = [[NSMutableString alloc] initWithFormat:@"<%@ %p capacity=%u, count=%u (%@",
NSStringFromClass([self class]), self, _capacity, _count, multiline ? @"\n" : @""];
for (NSUInteger i = 0; i < _count; ++i) {
const BOOL last = (i == _count - 1);
[description appendFormat:@"%@%@%@%@",
multiline ? @"\t" : @"",
[self objectAtIndex:i],
last ? @"" : @",",
multiline ? @"\n" : @""];
}
[description appendString:@")>"];
return description;
}
#pragma mark - <NSFastEnumeration>
- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id __unsafe_unretained [])buffer count:(NSUInteger)len {
if (state->state == 0) {
state->mutationsPtr = &_mutationCounter;
}
NSUInteger subcount = 0;
if (state->state < _count) {
state->itemsPtr = buffer;
while (state->state < _count && subcount < len) {
buffer[subcount] = [self objectAtIndex:state->state];
state->state += 1;
subcount += 1;
}
}
return subcount;
}
@end
@anastasiadevana
Copy link

@werediver, yeah, I figured out the NSNumber wrapping "trick", but wasn't sure if that makes sense performance-wise. I also have zero experience with Swift, haha, but I'll figure something out. Appreciate the quick response!

@werediver
Copy link
Author

@anastasiadevana About wrapping in NSNumber and performance: yes, NSNumber is "heavier" than a double, but as with any performance doubt, first test if you need to optimize. May just work well for you. NSNumber is quite heavily optimized under the hood (even though it's difficult to find a single reference describing the optimizations).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment