2014-05-06 19:41:08 +02:00
|
|
|
#import "CyclicalBuffer.h"
|
|
|
|
#import "Constraints.h"
|
|
|
|
#import "Util.h"
|
|
|
|
|
2014-07-17 02:02:09 +02:00
|
|
|
#define INITIAL_CAPACITY 100 // The buffer size can not be longer than an unsigned int.
|
2014-05-06 19:41:08 +02:00
|
|
|
|
|
|
|
@implementation CyclicalBuffer
|
|
|
|
|
|
|
|
-(id) init {
|
|
|
|
if (self = [super init]) {
|
|
|
|
buffer = [NSMutableData dataWithLength:INITIAL_CAPACITY];
|
|
|
|
}
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
-(void) enqueueData:(NSData*)data {
|
|
|
|
require(data != nil);
|
2014-08-14 03:13:24 +02:00
|
|
|
if(data.length == 0) return;
|
2014-05-06 19:41:08 +02:00
|
|
|
|
2014-08-14 03:13:24 +02:00
|
|
|
NSUInteger incomingDataLength = data.length;
|
|
|
|
NSUInteger bufferCapacity = buffer.length;
|
2014-05-06 19:41:08 +02:00
|
|
|
NSUInteger writeOffset = (readOffset + count) % bufferCapacity;
|
|
|
|
NSUInteger bufferSpaceAvailable = bufferCapacity - count;
|
|
|
|
NSUInteger writeSlack = bufferCapacity - writeOffset;
|
|
|
|
|
|
|
|
if (bufferSpaceAvailable < incomingDataLength) {
|
|
|
|
NSUInteger readSlack = bufferCapacity - readOffset;
|
|
|
|
NSUInteger newCapacity = bufferCapacity * 2 + incomingDataLength;
|
|
|
|
NSMutableData* newBuffer = [NSMutableData dataWithLength:newCapacity];
|
|
|
|
[newBuffer replaceBytesInRange:NSMakeRange(0, MIN(readSlack, count)) withBytes:(uint8_t*)[buffer bytes] + readOffset];
|
|
|
|
if (readSlack < count) {
|
|
|
|
[newBuffer replaceBytesInRange:NSMakeRange(readSlack, count - readSlack) withBytes:(uint8_t*)[buffer bytes]];
|
|
|
|
}
|
|
|
|
buffer = newBuffer;
|
|
|
|
bufferCapacity = newCapacity;
|
|
|
|
readOffset = 0;
|
|
|
|
writeOffset = count;
|
|
|
|
bufferSpaceAvailable = bufferCapacity - count;
|
|
|
|
writeSlack = bufferCapacity - writeOffset;
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(bufferSpaceAvailable >= incomingDataLength);
|
|
|
|
|
|
|
|
[buffer replaceBytesInRange:NSMakeRange(writeOffset, MIN(writeSlack, incomingDataLength)) withBytes:[data bytes]];
|
|
|
|
if (incomingDataLength > writeSlack) {
|
|
|
|
[buffer replaceBytesInRange:NSMakeRange(0, incomingDataLength - writeSlack) withBytes:(uint8_t*)[data bytes] + writeSlack];
|
|
|
|
}
|
2014-08-14 03:13:24 +02:00
|
|
|
count += data.length;
|
2014-05-06 19:41:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
-(NSUInteger) enqueuedLength {
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
-(void) discard:(NSUInteger)length {
|
|
|
|
require(length <= count);
|
|
|
|
count -= length;
|
2014-08-14 03:13:24 +02:00
|
|
|
readOffset = (readOffset + length)%(unsigned int)buffer.length;
|
2014-05-06 19:41:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
-(NSData*) peekDataWithLength:(NSUInteger)length{
|
|
|
|
require(length <= count);
|
|
|
|
if (length == 0) return [NSData data];
|
|
|
|
|
2014-08-14 03:13:24 +02:00
|
|
|
NSUInteger readSlack = buffer.length - readOffset;
|
2014-05-06 19:41:08 +02:00
|
|
|
|
|
|
|
NSMutableData* result = [NSMutableData dataWithLength:length];
|
|
|
|
[result replaceBytesInRange:NSMakeRange(0, MIN(readSlack, length)) withBytes:(uint8_t*)[buffer bytes] + readOffset];
|
|
|
|
if (readSlack < length) {
|
|
|
|
[result replaceBytesInRange:NSMakeRange(readSlack, length - readSlack) withBytes:[buffer bytes]];
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
-(NSData*) dequeueDataWithLength:(NSUInteger)length {
|
|
|
|
NSData* result = [self peekDataWithLength:length];
|
|
|
|
[self discard:length];
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
-(NSData*) dequeuePotentialyVolatileDataWithLength:(NSUInteger)length {
|
2014-08-14 03:13:24 +02:00
|
|
|
NSUInteger readSlack = buffer.length - readOffset;
|
2014-05-06 19:41:08 +02:00
|
|
|
|
|
|
|
if (readSlack < length) return [self dequeueDataWithLength:length];
|
|
|
|
|
|
|
|
NSData* result = [buffer subdataVolatileWithRange:NSMakeRange(readOffset, length)];
|
|
|
|
|
|
|
|
[self discard:length];
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
-(NSData*) peekVolatileHeadOfData {
|
2014-08-14 03:13:24 +02:00
|
|
|
NSUInteger capacity = buffer.length;
|
2014-05-06 19:41:08 +02:00
|
|
|
NSUInteger slack = capacity - readOffset;
|
|
|
|
return [buffer subdataVolatileWithRange:NSMakeRange(readOffset, MIN(count, slack))];
|
|
|
|
}
|
|
|
|
|
|
|
|
@end
|