/* * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_APACHE_LICENSE_HEADER_START@ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @APPLE_APACHE_LICENSE_HEADER_END@ */ // // cfdata.m // Copyright (c) 2008-2001 Apple. All rights reserved. // #import #import "BlackBoxTest.h" @interface _CFDataTestObject : NSObject { __strong CFDataRef subject; __strong CFMutableDataRef mutableSubject; __strong CFDataRef subjectCopy; __strong CFMutableDataRef mutableSubjectCopy; __strong CFMutableDataRef subjectMutableCopy; __strong CFMutableDataRef mutableSubjectMutableCopy; } - init; @end @interface _CFDataTestTestObject : _CFDataTestObject { bool shouldDealloc; __strong void *backingData; } @end @implementation _CFDataTestObject - (void) makeCopies { CFIndex size = 32*sizeof(void *); subjectCopy = CFDataCreateCopy(NULL, subject); mutableSubjectCopy = CFDataCreateMutableCopy(NULL, size, mutableSubject); subjectMutableCopy = CFDataCreateMutableCopy(NULL, size, subject); mutableSubjectMutableCopy = CFDataCreateMutableCopy(NULL, size, mutableSubject); } - (void)makeCollectable { CFMakeCollectable(subjectCopy); CFMakeCollectable(mutableSubjectCopy); CFMakeCollectable(subjectMutableCopy); CFMakeCollectable(mutableSubjectMutableCopy); CFMakeCollectable(subject); CFMakeCollectable(mutableSubject); } - (void)grow { CFIndex size = 32*sizeof(void *); CFDataSetLength(mutableSubjectCopy, 2*size); CFDataSetLength(subjectMutableCopy, 2*size); CFDataSetLength(mutableSubjectMutableCopy, 2*size); CFDataSetLength(mutableSubject, 2*size); } - (void)dealloc { CFRelease(subjectCopy); CFRelease(mutableSubjectCopy); CFRelease(subjectMutableCopy); CFRelease(mutableSubjectMutableCopy); CFRelease(subject); CFRelease(mutableSubject); [super dealloc]; } - init { id buffer[32]; for (int i = 0; i < 32; ++i) buffer[i] = self; CFIndex size = sizeof(void *)*32; if (!subject) subject = CFDataCreate(NULL, (uint8_t *)buffer, size); mutableSubject = CFDataCreateMutable(NULL, size); const UInt8 *bytes = CFDataGetBytePtr((CFMutableDataRef)mutableSubject); memcpy((void *)bytes, buffer, size); [self makeCopies]; [self makeCollectable]; [self grow]; return self; } static bool allSame(void *value, void **items, int nitems) { for (int i = 0; i < nitems; ++i) if (items[i] != value) return false; return true; } - (void)test { bool result = true; CFIndex count = CFDataGetLength(subject)/sizeof(void *); result = result && allSame(self, (void **)CFDataGetBytePtr(subject), count); result = result && allSame(self, (void **)CFDataGetBytePtr(mutableSubject), count); result = result && allSame(self, (void **)CFDataGetBytePtr(subjectCopy), count); result = result && allSame(self, (void **)CFDataGetBytePtr(mutableSubjectCopy), count); result = result && allSame(self, (void **)CFDataGetBytePtr(subjectMutableCopy), count); result = result && allSame(self, (void **)CFDataGetBytePtr(mutableSubjectMutableCopy), count); if (!result) { [[TestCase currentTestCase] fail:@"data changed!"]; } } @end @implementation _CFDataTestTestObject - (void)allocateBacking:(CFIndex)size { backingData = malloc_zone_malloc((malloc_zone_t*)NSDefaultMallocZone(), size); } - init { id buffer[32]; for (int i = 0; i < 32; ++i) buffer[i] = self; CFIndex size = sizeof(void *)*32; [self allocateBacking:size]; memcpy(backingData, buffer, size); subject = CFDataCreateWithBytesNoCopy(NULL, (const UInt8*)backingData, size, NULL); //if ([NSGarbageCollector defaultCollector]) printf("backing data %p held by %p\n", backingData, subject); return [super init]; } - initExplicit { id buffer[32]; for (int i = 0; i < 32; ++i) buffer[i] = self; CFIndex size = sizeof(void *)*32; [self allocateBacking:size]; memcpy(backingData, buffer, size); // explicitly use kCFAllocatorDefault subject = CFDataCreateWithBytesNoCopy(NULL, (const UInt8*)backingData, size, kCFAllocatorDefault); //if ([NSGarbageCollector defaultCollector]) printf("backing data %p held by %p\n", backingData, subject); return [super init]; } - initOwned { id buffer[32]; for (int i = 0; i < 32; ++i) buffer[i] = self; CFIndex size = sizeof(void *)*32; [self allocateBacking:size]; memcpy(backingData, buffer, size); // explicitly use kCFAllocatorNull to say that the memory is owned elsewhere subject = CFDataCreateWithBytesNoCopy(NULL, (const UInt8*)backingData, size, kCFAllocatorNull); shouldDealloc = true; //if ([NSGarbageCollector defaultCollector]) printf("backing data %p held by %p, will dealloc\n", backingData, subject); return [super init]; } - (void) dealloc { if (shouldDealloc) free(backingData); [super dealloc]; } - (void) finalize { if (shouldDealloc) free(backingData); [super finalize]; } @end #define LOOPS 10 @interface CFDataTest : BlackBoxTest @end @implementation CFDataTest - (void)testLoop { NSMutableArray *array = [[NSMutableArray alloc] init]; for (int i = 0; i < LOOPS; ++i) { _CFDataTestObject *to = [[_CFDataTestObject alloc] init]; [array addObject:to]; [to release]; } for (int i = 0; i < LOOPS; ++i) { _CFDataTestTestObject *to = [[_CFDataTestTestObject alloc] init]; [array addObject:to]; [to release]; } for (int i = 0; i < LOOPS; ++i) { _CFDataTestTestObject *to = [[_CFDataTestTestObject alloc] initExplicit]; [array addObject:to]; [to release]; } for (int i = 0; i < LOOPS; ++i) { _CFDataTestTestObject *to = [[_CFDataTestTestObject alloc] initOwned]; [array addObject:to]; [to release]; } [array release]; } - (void)performTest { for (int i = 0; i < (1+LOOPS); ++i) { // just enough for GC to not find things on the stack [self testLoop]; } [self clearStack]; [self requestFullCollectionWithCompletionCallback:^{ [self passed]; [self testFinished]; }]; } @end