mirror of
https://github.com/gnustep/libs-base.git
synced 2025-04-23 00:41:02 +00:00
Add [NSData initWithBytesNoCopy:length:deallocator:]
This new initializer allows customising the deallocation behaviour through user-supplied blocks. git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@40035 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
525d467e18
commit
c2be055c3e
4 changed files with 332 additions and 36 deletions
|
@ -1,3 +1,12 @@
|
|||
2016-07-26 Niels Grewe <niels.grewe@halbordnung.de>
|
||||
|
||||
* Headers/Foundation/NSData.h
|
||||
* Source/NSData.m
|
||||
* Tests/base/NSData/general.m:
|
||||
Implement OS X 10.9 method -initWithBytesNoCopy:length:deallocator:
|
||||
that allows customising data deallocation based on a caller
|
||||
supplied block. Also adds test cases for this functionality.
|
||||
|
||||
2016-07-26 Richard Frith-Macdonald <rfm@gnu.org>
|
||||
|
||||
* Source/GSStream.m:
|
||||
|
|
|
@ -3,24 +3,24 @@
|
|||
|
||||
Written by: Andrew Kachites McCallum <mccallum@gnu.ai.mit.edu>
|
||||
Date: 1995
|
||||
|
||||
|
||||
This file is part of the GNUstep Base Library.
|
||||
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02111 USA.
|
||||
*/
|
||||
*/
|
||||
|
||||
#ifndef __NSData_h_GNUSTEP_BASE_INCLUDE
|
||||
#define __NSData_h_GNUSTEP_BASE_INCLUDE
|
||||
|
@ -29,6 +29,7 @@
|
|||
#import <Foundation/NSObject.h>
|
||||
#import <Foundation/NSRange.h>
|
||||
#import <Foundation/NSSerialization.h>
|
||||
#import <GNUstepBase/GSBlocks.h>
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
|
@ -39,7 +40,7 @@ extern "C" {
|
|||
@class NSURL;
|
||||
#endif
|
||||
|
||||
#if OS_API_VERSION(MAC_OS_X_VERSION_10_9,GS_API_LATEST)
|
||||
#if OS_API_VERSION(MAC_OS_X_VERSION_10_9,GS_API_LATEST)
|
||||
enum {
|
||||
NSDataBase64DecodingIgnoreUnknownCharacters = (1UL << 0)
|
||||
};
|
||||
|
@ -54,7 +55,7 @@ enum {
|
|||
typedef NSUInteger NSDataBase64EncodingOptions;
|
||||
#endif
|
||||
|
||||
#if OS_API_VERSION(MAC_OS_X_VERSION_10_4,GS_API_LATEST)
|
||||
#if OS_API_VERSION(MAC_OS_X_VERSION_10_4,GS_API_LATEST)
|
||||
enum {
|
||||
NSMappedRead = 1,
|
||||
NSUncachedRead = 2
|
||||
|
@ -68,6 +69,10 @@ enum {
|
|||
#define NSAtomicWrite NSDataWritingAtomic
|
||||
#endif
|
||||
|
||||
#if OS_API_VERSION(MAC_OS_X_VERSION_10_9,GS_API_LATEST)
|
||||
DEFINE_BLOCK_TYPE(GSDataDeallocatorBlock, void, void*, NSUInteger);
|
||||
#endif
|
||||
|
||||
@interface NSData : NSObject <NSCoding, NSCopying, NSMutableCopying>
|
||||
|
||||
// Allocating and Initializing a Data Object
|
||||
|
@ -88,11 +93,20 @@ enum {
|
|||
+ (id) dataWithContentsOfURL: (NSURL*)url;
|
||||
#endif
|
||||
+ (id) dataWithData: (NSData*)data;
|
||||
#if OS_API_VERSION(MAC_OS_X_VERSION_10_9,GS_API_LATEST)
|
||||
#if OS_API_VERSION(MAC_OS_X_VERSION_10_9,GS_API_LATEST)
|
||||
- (id) initWithBase64EncodedData: (NSData*)base64Data
|
||||
options: (NSDataBase64DecodingOptions)options;
|
||||
- (id) initWithBase64EncodedString: (NSString*)base64String
|
||||
options: (NSDataBase64DecodingOptions)options;
|
||||
/**
|
||||
* <override-subclass/>
|
||||
* Initialize the receiver to hold memory pointed to by bytes without copying.
|
||||
* When the receiver is deallocated, the memory will be freed using the user
|
||||
* supplied deallocator block.
|
||||
*/
|
||||
- (instancetype) initWithBytesNoCopy: (void*)bytes
|
||||
length: (NSUInteger)length
|
||||
deallocator: (GSDataDeallocatorBlock)deallocator;
|
||||
#endif
|
||||
- (id) initWithBytes: (const void*)aBuffer
|
||||
length: (NSUInteger)bufferSize;
|
||||
|
@ -110,7 +124,7 @@ enum {
|
|||
#endif
|
||||
- (id) initWithData: (NSData*)data;
|
||||
|
||||
// Accessing Data
|
||||
// Accessing Data
|
||||
|
||||
- (const void*) bytes;
|
||||
- (NSString*) description;
|
||||
|
@ -122,11 +136,11 @@ enum {
|
|||
- (NSData*) subdataWithRange: (NSRange)aRange;
|
||||
|
||||
// base64
|
||||
#if OS_API_VERSION(MAC_OS_X_VERSION_10_9,GS_API_LATEST)
|
||||
#if OS_API_VERSION(MAC_OS_X_VERSION_10_9,GS_API_LATEST)
|
||||
- (NSData *) base64EncodedDataWithOptions: (NSDataBase64EncodingOptions)options;
|
||||
- (NSString *) base64EncodedStringWithOptions: (NSDataBase64EncodingOptions)options;
|
||||
#endif
|
||||
|
||||
|
||||
// Querying a Data Object
|
||||
|
||||
- (BOOL) isEqualToData: (NSData*)other;
|
||||
|
@ -171,7 +185,7 @@ enum {
|
|||
count: (unsigned int)numInts
|
||||
atIndex: (unsigned int)index;
|
||||
|
||||
#if OS_API_VERSION(MAC_OS_X_VERSION_10_4,GS_API_LATEST)
|
||||
#if OS_API_VERSION(MAC_OS_X_VERSION_10_4,GS_API_LATEST)
|
||||
/**
|
||||
* <p>Writes a copy of the data encapsulated by the receiver to a file
|
||||
* at path. If the NSDataWritingAtomic option is set, this writes to a
|
||||
|
|
219
Source/NSData.m
219
Source/NSData.m
|
@ -52,10 +52,12 @@
|
|||
* NSDataMappedFile Memory mapped files.
|
||||
* NSDataShared Extension for shared memory.
|
||||
* NSDataFinalized For GC of non-GC data.
|
||||
* NSDataWithDeallocatorBlock Adds custom deallocation behaviour
|
||||
* NSMutableData Abstract base class.
|
||||
* NSMutableDataMalloc Concrete class.
|
||||
* NSMutableDataShared Extension for shared memory.
|
||||
* NSDataMutableFinalized For GC of non-GC data.
|
||||
* NSMutableDataWithDeallocatorBlock Adds custom deallocation behaviour
|
||||
*
|
||||
* NSMutableDataMalloc MUST share it's initial instance variable layout
|
||||
* with NSDataMalloc so that it can use the 'behavior' code to inherit
|
||||
|
@ -126,6 +128,8 @@
|
|||
static Class dataStatic;
|
||||
static Class dataMalloc;
|
||||
static Class mutableDataMalloc;
|
||||
static Class dataBlock;
|
||||
static Class mutableDataBlock;
|
||||
static Class NSDataAbstract;
|
||||
static Class NSMutableDataAbstract;
|
||||
static SEL appendSel;
|
||||
|
@ -390,6 +394,13 @@ failure:
|
|||
@interface NSDataMalloc : NSDataStatic
|
||||
@end
|
||||
|
||||
@interface NSDataWithDeallocatorBlock : NSDataMalloc
|
||||
{
|
||||
@private
|
||||
GSDataDeallocatorBlock _deallocator;
|
||||
}
|
||||
@end
|
||||
|
||||
@interface NSMutableDataMalloc : NSMutableData
|
||||
{
|
||||
NSUInteger length;
|
||||
|
@ -402,6 +413,13 @@ failure:
|
|||
- (void) _grow: (NSUInteger)minimum;
|
||||
@end
|
||||
|
||||
@interface NSMutableDataWithDeallocatorBlock : NSMutableDataMalloc
|
||||
{
|
||||
@private
|
||||
GSDataDeallocatorBlock _deallocator;
|
||||
}
|
||||
@end
|
||||
|
||||
#ifdef HAVE_MMAP
|
||||
@interface NSDataMappedFile : NSDataMalloc
|
||||
@end
|
||||
|
@ -445,7 +463,9 @@ failure:
|
|||
NSMutableDataAbstract = [NSMutableData class];
|
||||
dataStatic = [NSDataStatic class];
|
||||
dataMalloc = [NSDataMalloc class];
|
||||
dataBlock = [NSDataWithDeallocatorBlock class];
|
||||
mutableDataMalloc = [NSMutableDataMalloc class];
|
||||
mutableDataBlock = [NSMutableDataWithDeallocatorBlock class];
|
||||
appendSel = @selector(appendBytes:length:);
|
||||
appendImp = [mutableDataMalloc instanceMethodForSelector: appendSel];
|
||||
}
|
||||
|
@ -824,6 +844,14 @@ failure:
|
|||
return nil;
|
||||
}
|
||||
|
||||
- (instancetype) initWithBytesNoCopy: (void*)bytes
|
||||
length: (NSUInteger)length
|
||||
deallocator: (GSDataDeallocatorBlock)deallocator
|
||||
{
|
||||
[self subclassResponsibility: _cmd];
|
||||
return nil;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialises the receiver with the contents of the specified file.<br />
|
||||
* Returns the resulting object.<br />
|
||||
|
@ -3300,6 +3328,37 @@ getBytes(void* dst, void* src, unsigned len, unsigned limit, unsigned *pos)
|
|||
return self;
|
||||
}
|
||||
|
||||
- (instancetype) initWithBytesNoCopy: (void*)buf
|
||||
length: (NSUInteger)len
|
||||
deallocator: (GSDataDeallocatorBlock)deallocator
|
||||
{
|
||||
if (buf == NULL && len > 0)
|
||||
{
|
||||
[self release];
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"[%@-initWithBytesNoCopy:length:deallocator:] called with "
|
||||
@"length but NULL bytes", NSStringFromClass([self class])];
|
||||
}
|
||||
else if (NULL == deallocator)
|
||||
{
|
||||
// For a nil deallocator we can just swizzle into a static data object
|
||||
GSClassSwizzle(self, dataStatic);
|
||||
bytes = buf;
|
||||
length = len;
|
||||
return self;
|
||||
}
|
||||
|
||||
/* This is a bit unfortunate: Our implementation has no space to hold the
|
||||
* deallocator block ivar in NSDataMalloc, so if we are invoked via this
|
||||
* initialiser, we have to undo the previous allocation and reallocate
|
||||
* ourselves as NSDataWithDeallocatorBlock.
|
||||
*/
|
||||
[self release];
|
||||
return [[dataBlock alloc] initWithBytesNoCopy: buf
|
||||
length: len
|
||||
deallocator: deallocator];
|
||||
}
|
||||
|
||||
- (NSUInteger) sizeInBytesExcluding: (NSHashTable*)exclude
|
||||
{
|
||||
NSUInteger size = GSPrivateMemorySize(self, exclude);
|
||||
|
@ -3313,6 +3372,38 @@ getBytes(void* dst, void* src, unsigned len, unsigned limit, unsigned *pos)
|
|||
|
||||
@end
|
||||
|
||||
@implementation NSDataWithDeallocatorBlock
|
||||
- (instancetype) initWithBytesNoCopy: (void*)buf
|
||||
length: (NSUInteger)len
|
||||
deallocator: (GSDataDeallocatorBlock)deallocator
|
||||
{
|
||||
if (buf == NULL && len > 0)
|
||||
{
|
||||
[self release];
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"[%@-initWithBytesNoCopy:length:deallocator:] called with "
|
||||
@"length but NULL bytes", NSStringFromClass([self class])];
|
||||
}
|
||||
|
||||
bytes = buf;
|
||||
length = len;
|
||||
ASSIGN(_deallocator, deallocator);
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
if (_deallocator != NULL)
|
||||
{
|
||||
CALL_BLOCK(_deallocator, bytes, length);
|
||||
}
|
||||
// Clear out the ivars so that super doesn't double free.
|
||||
bytes = NULL;
|
||||
length = 0;
|
||||
[super dealloc];
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
#ifdef HAVE_MMAP
|
||||
@implementation NSDataMappedFile
|
||||
|
@ -3609,6 +3700,35 @@ getBytes(void* dst, void* src, unsigned len, unsigned limit, unsigned *pos)
|
|||
return self;
|
||||
}
|
||||
|
||||
- (instancetype) initWithBytesNoCopy: (void*)buf
|
||||
length: (NSUInteger)len
|
||||
deallocator: (GSDataDeallocatorBlock)deallocator
|
||||
{
|
||||
if (buf == NULL && len > 0)
|
||||
{
|
||||
[self release];
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"[%@-initWithBytesNoCopy:length:deallocator:] called with "
|
||||
@"length but NULL bytes", NSStringFromClass([self class])];
|
||||
}
|
||||
else if (NULL == deallocator)
|
||||
{
|
||||
// Can reuse this class.
|
||||
return [self initWithBytesNoCopy: buf
|
||||
length: len
|
||||
freeWhenDone: NO];
|
||||
}
|
||||
|
||||
/*
|
||||
* Custom deallocator. Need to re-allocate as an instance of
|
||||
* NSMutableDataWithDeallocatorBlock
|
||||
*/
|
||||
[self release];
|
||||
return [[mutableDataBlock alloc] initWithBytesNoCopy: buf
|
||||
length: len
|
||||
deallocator: deallocator];
|
||||
}
|
||||
|
||||
// THIS IS THE DESIGNATED INITIALISER
|
||||
/**
|
||||
* Initialize with buffer capable of holding size bytes.
|
||||
|
@ -4108,6 +4228,105 @@ getBytes(void* dst, void* src, unsigned len, unsigned limit, unsigned *pos)
|
|||
|
||||
@end
|
||||
|
||||
@implementation NSMutableDataWithDeallocatorBlock
|
||||
|
||||
+ (id) allocWithZone: (NSZone*)z
|
||||
{
|
||||
return NSAllocateObject(mutableDataBlock, 0, z);
|
||||
}
|
||||
|
||||
- (instancetype) initWithBytesNoCopy: (void*)buf
|
||||
length: (NSUInteger)len
|
||||
deallocator: (GSDataDeallocatorBlock)deallocator
|
||||
{
|
||||
if (buf == NULL && len > 0)
|
||||
{
|
||||
[self release];
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"[%@-initWithBytesNoCopy:length:deallocator:] called with "
|
||||
@"length but NULL bytes", NSStringFromClass([self class])];
|
||||
}
|
||||
|
||||
/* The assumption here is that the superclass if fully concrete and will
|
||||
* not return a different instance. This invariant holds for the current
|
||||
* implementation of NSMutableDataMalloc, but not NSDataMalloc.
|
||||
*/
|
||||
if (nil == (self = [super initWithBytesNoCopy: buf
|
||||
length: len
|
||||
freeWhenDone: NO]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
ASSIGN(_deallocator, deallocator);
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
if (_deallocator != NULL)
|
||||
{
|
||||
CALL_BLOCK(_deallocator, bytes, capacity);
|
||||
// Clear out the ivars so that super doesn't double free.
|
||||
bytes = NULL;
|
||||
length = 0;
|
||||
DESTROY(_deallocator);
|
||||
}
|
||||
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (id) setCapacity: (NSUInteger)size
|
||||
{
|
||||
/* We need to override capacity modification so that we correctly call the
|
||||
* block when we are operating on the initial allocation, usual malloc/free
|
||||
* machinery otherwise. */
|
||||
if (size != capacity)
|
||||
{
|
||||
void *tmp;
|
||||
|
||||
tmp = NSZoneMalloc(zone, size);
|
||||
if (tmp == 0)
|
||||
{
|
||||
[NSException raise: NSMallocException
|
||||
format: @"Unable to set data capacity to '%"PRIuPTR"'", size];
|
||||
}
|
||||
if (bytes)
|
||||
{
|
||||
memcpy(tmp, bytes, capacity < size ? capacity : size);
|
||||
if (_deallocator != NULL)
|
||||
{
|
||||
CALL_BLOCK(_deallocator, bytes, capacity);
|
||||
DESTROY(_deallocator);
|
||||
zone = NSDefaultMallocZone();
|
||||
}
|
||||
else
|
||||
{
|
||||
NSZoneFree(zone, bytes);
|
||||
}
|
||||
}
|
||||
else if (_deallocator != NULL)
|
||||
{
|
||||
CALL_BLOCK(_deallocator, bytes, capacity);
|
||||
DESTROY(_deallocator);
|
||||
zone = NSDefaultMallocZone();
|
||||
}
|
||||
bytes = tmp;
|
||||
capacity = size;
|
||||
growth = capacity/2;
|
||||
if (growth == 0)
|
||||
{
|
||||
growth = 1;
|
||||
}
|
||||
}
|
||||
if (size < length)
|
||||
{
|
||||
length = size;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
#ifdef HAVE_SHMCTL
|
||||
@implementation NSMutableDataShared
|
||||
|
|
|
@ -5,20 +5,20 @@
|
|||
#import <Foundation/NSString.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
{
|
||||
NSAutoreleasePool *arp = [NSAutoreleasePool new];
|
||||
char *str1,*str2;
|
||||
NSData *data1, *data2;
|
||||
NSMutableData *mutable;
|
||||
char *hold;
|
||||
|
||||
|
||||
str1 = "Test string for data classes";
|
||||
str2 = (char *) malloc(sizeof("Test string for data classes not copied"));
|
||||
str2 = (char *) malloc(sizeof("Test string for data classes not copied"));
|
||||
strcpy(str2,"Test string for data classes not copied");
|
||||
|
||||
|
||||
mutable = [NSMutableData dataWithLength:100];
|
||||
hold = [mutable mutableBytes];
|
||||
|
||||
hold = [mutable mutableBytes];
|
||||
|
||||
/* hmpf is this correct */
|
||||
data1 = [NSData dataWithBytes:str1 length:(strlen(str1) * sizeof(void*))];
|
||||
PASS(data1 != nil &&
|
||||
|
@ -27,52 +27,106 @@ int main()
|
|||
[data1 bytes] != str1 &&
|
||||
strcmp(str1,[data1 bytes]) == 0,
|
||||
"+dataWithBytes:length: works");
|
||||
|
||||
|
||||
data2 = [NSData dataWithBytesNoCopy:str2 length:(strlen(str2) * sizeof(void*))];
|
||||
PASS(data2 != nil && [data2 isKindOfClass:[NSData class]] &&
|
||||
[data2 length] == (strlen(str2) * sizeof(void*)) &&
|
||||
[data2 bytes] == str2,
|
||||
"+dataWithBytesNoCopy:length: works");
|
||||
|
||||
|
||||
data1 = [NSData dataWithBytes:nil length:0];
|
||||
PASS(data1 != nil && [data1 isKindOfClass:[NSData class]] &&
|
||||
[data1 length] == 0,
|
||||
PASS(data1 != nil && [data1 isKindOfClass:[NSData class]] &&
|
||||
[data1 length] == 0,
|
||||
"+dataWithBytes:length works with 0 length");
|
||||
|
||||
[data2 getBytes:hold range:NSMakeRange(2,6)];
|
||||
|
||||
[data2 getBytes:hold range:NSMakeRange(2,6)];
|
||||
PASS(strcmp(hold,"st str") == 0, "-getBytes:range works");
|
||||
|
||||
PASS_EXCEPTION([data2 getBytes:hold
|
||||
|
||||
PASS_EXCEPTION([data2 getBytes:hold
|
||||
range:NSMakeRange(strlen(str2)*sizeof(void*),1)];,
|
||||
NSRangeException,
|
||||
"getBytes:range: with bad location");
|
||||
|
||||
PASS_EXCEPTION([data2 getBytes:hold
|
||||
|
||||
PASS_EXCEPTION([data2 getBytes:hold
|
||||
range:NSMakeRange(1,(strlen(str2)*sizeof(void*)))];,
|
||||
NSRangeException,
|
||||
"getBytes:range: with bad length");
|
||||
|
||||
|
||||
PASS_EXCEPTION([data2 subdataWithRange:NSMakeRange((strlen(str2)*sizeof(void*)),1)];,
|
||||
NSRangeException,
|
||||
"-subdataWithRange: with bad location");
|
||||
|
||||
|
||||
PASS_EXCEPTION([data2 subdataWithRange:NSMakeRange(1,(strlen(str2)*sizeof(void*)))];,
|
||||
NSRangeException,
|
||||
"-subdataWithRange: with bad length");
|
||||
|
||||
data2 = [NSData dataWithBytesNoCopy:str1
|
||||
|
||||
data2 = [NSData dataWithBytesNoCopy:str1
|
||||
length:(strlen(str1) * sizeof(void*))
|
||||
freeWhenDone:NO];
|
||||
PASS(data2 != nil && [data2 isKindOfClass:[NSData class]] &&
|
||||
[data2 length] == (strlen(str1) * sizeof(void*)) &&
|
||||
[data2 bytes] == str1,
|
||||
[data2 bytes] == str1,
|
||||
"+dataWithBytesNoCopy:length:freeWhenDone: works");
|
||||
|
||||
|
||||
[arp release]; arp = nil;
|
||||
|
||||
{
|
||||
|
||||
{
|
||||
BOOL didNotSegfault = YES;
|
||||
PASS(didNotSegfault, "+dataWithBytesNoCopy:length:freeWhenDone:NO doesn't free memory");
|
||||
}
|
||||
|
||||
|
||||
START_SET("deallocator blocks")
|
||||
# ifndef __has_feature
|
||||
# define __has_feature(x) 0
|
||||
# endif
|
||||
# if __has_feature(blocks)
|
||||
uint8_t stackBuf[4] = { 1, 2, 3, 5 };
|
||||
__block NSUInteger called = 0;
|
||||
NSData *immutable =
|
||||
[[NSData alloc] initWithBytesNoCopy: stackBuf
|
||||
length: 4
|
||||
deallocator: ^(void* bytes, NSUInteger length) {
|
||||
called++;
|
||||
}];
|
||||
PASS_RUNS([immutable release]; immutable = nil;,
|
||||
"No free() error with custom deallocator");
|
||||
PASS(called == 1, "Deallocator block called");
|
||||
uint8_t *buf = malloc(4 * sizeof(uint8_t));
|
||||
NSMutableData *mutable =
|
||||
[[NSMutableData alloc] initWithBytesNoCopy: buf
|
||||
length: 4
|
||||
deallocator: ^(void *bytes, NSUInteger len)
|
||||
{
|
||||
free(bytes);
|
||||
called++;
|
||||
}
|
||||
];
|
||||
PASS_RUNS([mutable release]; mutable = nil;,
|
||||
"No free() error with custom deallocator on mutable data");
|
||||
PASS(called == 2, "Deallocator block called on -dealloc of mutable data");
|
||||
buf = malloc(4 * sizeof(uint8_t));
|
||||
mutable =
|
||||
[[NSMutableData alloc] initWithBytesNoCopy: buf
|
||||
length: 4
|
||||
deallocator: ^(void *bytes, NSUInteger len)
|
||||
{
|
||||
free(bytes);
|
||||
called++;
|
||||
}
|
||||
];
|
||||
PASS_RUNS([mutable setCapacity: 10];,
|
||||
"Can set capactiy with custom deallocator on mutable data");
|
||||
PASS(called == 3,
|
||||
"Deallocator block called on -setCapacity: of mutable data");
|
||||
PASS_RUNS([mutable release]; mutable = nil;,
|
||||
"No free() error with custom deallocator on mutable data "
|
||||
"after capacity change");
|
||||
PASS(called == 3, "Deallocator block not called on -dealloc of mutable data "
|
||||
"after its capacity has been changed");
|
||||
# else
|
||||
SKIP("No Blocks support in the compiler.")
|
||||
# endif
|
||||
END_SET("deallocator blocks")
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue