Created
August 27, 2013 14:34
-
-
Save fjolnir/6354354 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import <ObjFW/ObjFW.h> | |
@interface OFBuffer : OFObject { | |
size_t _length, _capacity; | |
void *_bytes; | |
BOOL _externalStorage, _freeWhenDone; | |
} | |
// This pointer is only guaranteed to be valid as long as the | |
// OFBuffer object remains unchanged. | |
@property(readonly) void *bytes; | |
@property size_t length; | |
+ (OFBuffer *)bufferWithLength:(size_t)length capacity:(size_t)capacity; | |
- (id)initWithLength:(size_t)length capacity:(size_t)capacity; | |
- (id)initWithBytes:(const void *)bytes length:(size_t)length; | |
- (id)initWithBytesNoCopy:(const void *)bytes length:(size_t)length freeWhenDone:(BOOL)freeWhenDone; | |
- (void)getBytes:(void *)outBuf range:(of_range_t)range; | |
- (void)getBytes:(void *)outBuf length:(size_t)length; | |
- (void)getBytes:(void *)outBuf; | |
- (void)appendBytes:(const void *)bytes length:(size_t)length; | |
- (void)appendBuffer:(OFBuffer *)buffer; | |
- (void)replaceBytesInRange:(of_range_t)range withBytes:(const void *)bytes; | |
- (void)replaceBytesInRange:(of_range_t)range withBytes:(const void *)bytes length:(size_t)bytesLength; | |
- (void)resetBytesInRange:(of_range_t)range; | |
@end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import "OFBuffer.h" | |
#import <assert.h> | |
#import <string.h> | |
@interface OFBuffer () | |
- (void)_ensureFit:(size_t)length; | |
@end | |
@implementation OFBuffer | |
@synthesize length=_length, bytes=_bytes; | |
+ (OFBuffer *)bufferWithLength:(size_t)length capacity:(size_t)capacity | |
{ | |
return [[self alloc] initWithLength:length capacity:capacity]; | |
} | |
- (id)initWithLength:(size_t)length capacity:(size_t)capacity | |
{ | |
if((self = [super init])) { | |
_length = length; | |
_capacity = capacity == 0 ? length : capacity; | |
_bytes = malloc(_capacity); | |
} | |
return self; | |
} | |
- (id)initWithBytes:(const void *)bytes length:(size_t)length | |
{ | |
if((self = [self initWithLength:0 capacity:length])) { | |
[self appendBytes:bytes length:length]; | |
} | |
return self; | |
} | |
- (id)initWithBytesNoCopy:(const void *)bytes | |
length:(size_t)length | |
freeWhenDone:(BOOL)freeWhenDone | |
{ | |
if((self = [super init])) { | |
_externalStorage = YES; | |
_freeWhenDone = freeWhenDone; | |
_length = length; | |
_capacity = length; | |
_bytes = (void *)bytes; | |
} | |
return self; | |
} | |
- (void)dealloc | |
{ | |
if(!_externalStorage || (_externalStorage && _freeWhenDone)) | |
free(_bytes); | |
} | |
- (void)_copyStorageIfNeeded | |
{ | |
if(_externalStorage) { | |
void *extBuf = _bytes; | |
_bytes = malloc(_capacity); | |
if(_freeWhenDone) | |
free(extBuf); | |
_externalStorage = NO; | |
} | |
} | |
- (void *)bytes | |
{ | |
[self _copyStorageIfNeeded]; | |
return _bytes; | |
} | |
- (void)getBytes:(void *)outBuf range:(of_range_t)range | |
{ | |
assert(range.location + range.length < _length); | |
memcpy(outBuf, _bytes + range.location, range.length); | |
} | |
- (void)getBytes:(void *)outBuf length:(size_t)length | |
{ | |
[self getBytes:outBuf range:(of_range_t) { 0, length }]; | |
} | |
- (void)getBytes:(void *)outBuf | |
{ | |
[self getBytes:outBuf length:_length]; | |
} | |
- (void)_ensureFit:(size_t)length; | |
{ | |
[self _copyStorageIfNeeded]; | |
if(length > _capacity) { | |
_capacity *= 1.5; | |
_bytes = realloc(_bytes, _capacity); | |
} | |
} | |
- (void)appendBytes:(const void *)bytes length:(size_t)length | |
{ | |
size_t newLength = _length + length; | |
[self _ensureFit:length]; | |
memcpy(_bytes + _length, bytes, length); | |
_length = newLength; | |
} | |
- (void)appendBuffer:(OFBuffer *)buffer | |
{ | |
[self appendBytes:buffer.bytes length:buffer.length]; | |
} | |
- (void)replaceBytesInRange:(of_range_t)range withBytes:(const void *)bytes | |
{ | |
[self replaceBytesInRange:range withBytes:bytes length:range.length]; | |
} | |
- (void)replaceBytesInRange:(of_range_t)range withBytes:(const void *)bytes length:(size_t)bytesLength | |
{ | |
assert(range.location + range.length < _length); | |
size_t const newLength = MAX(_length, MAX(range.location+range.length, range.location+bytesLength)); | |
[self _ensureFit:newLength]; | |
if(range.length != bytesLength) | |
memmove(_bytes + range.location + bytesLength, | |
_bytes + range.location + range.length, | |
_length - range.location - range.length); | |
memcpy(_bytes + range.location, bytes, bytesLength); | |
} | |
- (void)resetBytesInRange:(of_range_t)range | |
{ | |
assert(range.location+range.length < _length); | |
memset(_bytes + range.location, 0, range.length); | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment