Skip to content

Instantly share code, notes, and snippets.

@werediver
Created August 22, 2014 11:45
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • 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
@ilanl
Copy link

ilanl commented Jul 1, 2015

Roman,

I'm looking for something similar for my swift project, I have a sensor manager which needs to buffer the sensor data, in a efficient way while the producer of the sensor data is much faster than the consumer side. Would this implementation work ? Is it thread safe ?

@werediver
Copy link
Author

This implementation is not thread safe.

In general, circular queue will work for you if you can tolerate loss of (older) data.

@mvk84
Copy link

mvk84 commented Dec 12, 2016

What is the license applicable on the code? Can it be reused and packaged in commercial code?

@werediver
Copy link
Author

To @mvk84 and everyone interested: consider this source code as a work in Public Domain.

Public Domain mark

@anastasiadevana
Copy link

Would something like this work for "doubles" as opposed to objects? (I have zero experience with Objective-C)

@werediver
Copy link
Author

werediver commented Jun 16, 2021

@anastasiadevana This implementation is built around NSMutableArray, which can only contain objects, not primitive types. I'd suggest you considering writing new code in Swift (Swift and Objective-C play along well).

It shouldn't be too difficult to rework this implementation to use a C-style array to use with primitive types. Or wrap your doubles in NSNumber, but that's not very efficient.

@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