Skip to content

Instantly share code, notes, and snippets.

@mikelikespie
Created February 14, 2013 06:35
Show Gist options
  • Save mikelikespie/4950998 to your computer and use it in GitHub Desktop.
Save mikelikespie/4950998 to your computer and use it in GitHub Desktop.
Zero-Copy bridging between dispatch_data_t and NSData
//
// NSData+PIOAdditions.h
// PonyExpress
//
// Created by Michael Lewis on 2/13/13.
//
//
#import <Foundation/Foundation.h>
#import <dispatch/data.h>
@interface NSData (PIOAdditions)
+ (instancetype)dataWithDispatchData:(dispatch_data_t)data;
// returns a dispatch_data_t representation of this object.
// This does not copy the internal bytes
- (dispatch_data_t)copyDispatchData DISPATCH_RETURNS_RETAINED;
@end
//
// NSData+PIOAdditions.m
// PonyExpress
//
// Created by Michael Lewis on 2/13/13.
//
//
#import "Common.h"
#import "NSData+PIOAdditions.h"
// A way to do copyless dispatch data if the dispatch_data_t has just one segment.
@interface _PIOMappedDispatchData : NSData
- (instancetype)initWithData:(dispatch_data_t)data;
@end
@implementation NSData (PIOAdditions)
+ (instancetype)dataWithDispatchData:(dispatch_data_t)data;
{
return [[_PIOMappedDispatchData alloc] initWithData:data];
}
- (dispatch_data_t)copyDispatchData;
{
// just incase we are mutable;
CFDataRef immutableSelf = CFBridgingRetain([self copy]);
return dispatch_data_create(self.bytes, self.length, dispatch_get_main_queue(), ^{
CFRelease(immutableSelf);
});
}
@end
@implementation _PIOMappedDispatchData {
dispatch_data_t _data;
NSUInteger _length;
const void *_bytes;
}
- (instancetype)initWithData:(dispatch_data_t)data;
{
const void *buffer;
size_t size = 0;
data = dispatch_data_create_map(data, &buffer, &size);
self = [super init];
if (self != nil) {
_bytes = buffer;
_length = size;
_data = data;
} else {
sr_dispatch_release(data);
}
return self;
}
- (NSUInteger)length;
{
return _length;
}
- (const void *)bytes;
{
return _bytes;
}
- (dispatch_data_t)copyDispatchData;
{
sr_dispatch_retain(_data);
return _data;
}
- (void)dealloc
{
if (_data != NULL) {
sr_dispatch_release(_data);
}
}
- (id)copy;
{
return [[_PIOMappedDispatchData alloc] initWithData:_data];
}
@end
//
// NSDataTest.m
// PonyExpress
//
// Created by Michael Lewis on 2/13/13.
//
//
#import <SenTestingKit/SenTestingKit.h>
#import "NSData+PIOAdditions.h"
#import "Common.h"
@interface NSDataTest : SenTestCase
@end
@implementation NSDataTest
- (void)testEfficientForOneSegment;
{
dispatch_data_t data = dispatch_data_create("hello", 5, dispatch_get_main_queue(), DISPATCH_DATA_DESTRUCTOR_DEFAULT);
NSData *d1 = [NSData dataWithDispatchData:data];
dispatch_data_t newData = [d1 copyDispatchData];
STAssertEquals(newData, data, @"Should not have created a new data object since it was one segment");
sr_dispatch_release(data);
sr_dispatch_release(newData);
}
- (void)testEfficientForDataCopy;
{
NSData *data = [[NSData alloc] initWithBytes:"hello" length:5];
dispatch_data_t newData = [data copyDispatchData];
NSData *data2 = [NSData dataWithDispatchData:newData];
STAssertEquals(data.bytes, data2.bytes, @"Should all ahve the same buffer");
sr_dispatch_release(newData);
}
@end
@snej
Copy link

snej commented Sep 17, 2015

dispatch_data_t is already toll-free-bridged to NSData, so is this code necessary at all? The two methods here don't seem to do anything you can't do with a simple C typecast.

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