CF_EXPORT unsigned long _CFArrayFastEnumeration(CFArrayRef array, struct __objcFastEnumerationStateEquivalent *state, void *stackbuffer, unsigned long count) { CHECK_FOR_MUTATION(array); if (array->_count == 0) return 0; enum { ATSTART = 0, ATEND = 1 }; switch (__CFArrayGetType(array)) { case __kCFArrayImmutable: if (state->state == ATSTART) { /* first time */ static const unsigned long const_mu = 1; state->state = ATEND; state->mutationsPtr = (unsigned long *)&const_mu; state->itemsPtr = (unsigned long *)__CFArrayGetBucketsPtr(array); return array->_count; } return 0; case __kCFArrayDeque: if (state->state == ATSTART) { /* first time */ state->state = ATEND; state->mutationsPtr = (unsigned long *)&array->_mutations; state->itemsPtr = (unsigned long *)__CFArrayGetBucketsPtr(array); return array->_count; } return 0; } return 0; }
__private_extern__ CFArrayRef __CFArrayCreateCopy0(CFAllocatorRef allocator, CFArrayRef array) { CFArrayRef result; const CFArrayCallBacks *cb; struct __CFArrayBucket *buckets; CFAllocatorRef bucketsAllocator; void* bucketsBase; CFIndex numValues = CFArrayGetCount(array); CFIndex idx; if (CF_IS_OBJC(__kCFArrayTypeID, array)) { cb = &kCFTypeArrayCallBacks; } else { cb = __CFArrayGetCallBacks(array); } result = __CFArrayInit(allocator, __kCFArrayImmutable, numValues, cb); cb = __CFArrayGetCallBacks(result); // GC: use the new array's callbacks so we don't leak. buckets = __CFArrayGetBucketsPtr(result); bucketsAllocator = isStrongMemory(result) ? allocator : kCFAllocatorNull; bucketsBase = CF_IS_COLLECTABLE_ALLOCATOR(bucketsAllocator) ? (void *)auto_zone_base_pointer(objc_collectableZone(), buckets) : NULL; for (idx = 0; idx < numValues; idx++) { const void *value = CFArrayGetValueAtIndex(array, idx); if (NULL != cb->retain) { value = (void *)INVOKE_CALLBACK2(cb->retain, allocator, value); } __CFAssignWithWriteBarrier((void **)&buckets->_item, (void *)value); buckets++; } __CFArraySetCount(result, numValues); return result; }
__private_extern__ CFArrayRef __CFArrayCreate0(CFAllocatorRef allocator, const void **values, CFIndex numValues, const CFArrayCallBacks *callBacks) { CFArrayRef result; const CFArrayCallBacks *cb; struct __CFArrayBucket *buckets; CFAllocatorRef bucketsAllocator; void* bucketsBase; CFIndex idx; CFAssert2(0 <= numValues, __kCFLogAssertion, "%s(): numValues (%d) cannot be less than zero", __PRETTY_FUNCTION__, numValues); result = __CFArrayInit(allocator, __kCFArrayImmutable, numValues, callBacks); cb = __CFArrayGetCallBacks(result); buckets = __CFArrayGetBucketsPtr(result); bucketsAllocator = isStrongMemory(result) ? allocator : kCFAllocatorNull; bucketsBase = CF_IS_COLLECTABLE_ALLOCATOR(bucketsAllocator) ? (void *)auto_zone_base_pointer(objc_collectableZone(), buckets) : NULL; if (NULL != cb->retain) { for (idx = 0; idx < numValues; idx++) { __CFAssignWithWriteBarrier((void **)&buckets->_item, (void *)INVOKE_CALLBACK2(cb->retain, allocator, *values)); values++; buckets++; } } else { for (idx = 0; idx < numValues; idx++) { __CFAssignWithWriteBarrier((void **)&buckets->_item, (void *)*values); values++; buckets++; } } __CFArraySetCount(result, numValues); return result; }
/* This shouldn't be called if the array count is 0. */ CF_INLINE struct __CFArrayBucket *__CFArrayGetBucketAtIndex(CFArrayRef array, CFIndex idx) { switch (__CFArrayGetType(array)) { case __kCFArrayImmutable: case __kCFArrayDeque: return __CFArrayGetBucketsPtr(array) + idx; } return NULL; }
static void __CFArrayReleaseValues(CFArrayRef array, CFRange range, bool releaseStorageIfPossible) { const CFArrayCallBacks *cb = __CFArrayGetCallBacks(array); CFAllocatorRef allocator; CFIndex idx; switch (__CFArrayGetType(array)) { case __kCFArrayImmutable: if (NULL != cb->release && 0 < range.length && !hasBeenFinalized(array)) { // if we've been finalized then we know that // 1) we're using the standard callback on GC memory // 2) the slots don't' need to be zeroed struct __CFArrayBucket *buckets = __CFArrayGetBucketsPtr(array); allocator = __CFGetAllocator(array); for (idx = 0; idx < range.length; idx++) { INVOKE_CALLBACK2(cb->release, allocator, buckets[idx + range.location]._item); buckets[idx + range.location]._item = NULL; // GC: break strong reference. } } break; case __kCFArrayDeque: { struct __CFArrayDeque *deque = (struct __CFArrayDeque *)array->_store; if (0 < range.length && NULL != deque && !hasBeenFinalized(array)) { struct __CFArrayBucket *buckets = __CFArrayGetBucketsPtr(array); if (NULL != cb->release) { allocator = __CFGetAllocator(array); for (idx = 0; idx < range.length; idx++) { INVOKE_CALLBACK2(cb->release, allocator, buckets[idx + range.location]._item); buckets[idx + range.location]._item = NULL; // GC: break strong reference. } } else { for (idx = 0; idx < range.length; idx++) { buckets[idx + range.location]._item = NULL; // GC: break strong reference. } } } if (releaseStorageIfPossible && 0 == range.location && __CFArrayGetCount(array) == range.length) { allocator = __CFGetAllocator(array); if (NULL != deque) if (!CF_IS_COLLECTABLE_ALLOCATOR(allocator)) CFAllocatorDeallocate(allocator, deque); __CFArraySetCount(array, 0); // GC: _count == 0 ==> _store == NULL. ((struct __CFArray *)array)->_store = NULL; } break; } } }
static void __CFArrayReleaseValues(CFArrayRef array, CFRange range, bool releaseStorageIfPossible) { const CFArrayCallBacks *cb = __CFArrayGetCallBacks(array); CFAllocatorRef allocator; CFIndex idx; switch (__CFArrayGetType(array)) { case __kCFArrayImmutable: if (NULL != cb->release && 0 < range.length) { struct __CFArrayBucket *buckets = __CFArrayGetBucketsPtr(array); allocator = __CFGetAllocator(array); for (idx = 0; idx < range.length; idx++) { INVOKE_CALLBACK2(cb->release, allocator, buckets[idx + range.location]._item); } memset(buckets + range.location, 0, sizeof(struct __CFArrayBucket) * range.length); } break; case __kCFArrayDeque: { struct __CFArrayDeque *deque = (struct __CFArrayDeque *)array->_store; if (0 < range.length && NULL != deque) { struct __CFArrayBucket *buckets = __CFArrayGetBucketsPtr(array); if (NULL != cb->release) { allocator = __CFGetAllocator(array); for (idx = 0; idx < range.length; idx++) { INVOKE_CALLBACK2(cb->release, allocator, buckets[idx + range.location]._item); } } memset(buckets + range.location, 0, sizeof(struct __CFArrayBucket) * range.length); } if (releaseStorageIfPossible && 0 == range.location && __CFArrayGetCount(array) == range.length) { allocator = __CFGetAllocator(array); if (NULL != deque) CFAllocatorDeallocate(allocator, deque); __CFArraySetCount(array, 0); ((struct __CFArray *)array)->_store = NULL; } break; } } }
void CFArrayGetValues(CFArrayRef array, CFRange range, const void **values) { CF_OBJC_FUNCDISPATCHV(__kCFArrayTypeID, void, (NSArray *)array, getObjects:(id *)values range:NSMakeRange(range.location, range.length)); __CFGenericValidateType(array, __kCFArrayTypeID); __CFArrayValidateRange(array, range, __PRETTY_FUNCTION__); CFAssert1(NULL != values, __kCFLogAssertion, "%s(): pointer to values may not be NULL", __PRETTY_FUNCTION__); CHECK_FOR_MUTATION(array); if (0 < range.length) { switch (__CFArrayGetType(array)) { case __kCFArrayImmutable: case __kCFArrayDeque: objc_memmove_collectable(values, __CFArrayGetBucketsPtr(array) + range.location, range.length * sizeof(struct __CFArrayBucket)); break; } } }
__private_extern__ CFArrayRef __CFArrayCreateTransfer(CFAllocatorRef allocator, const void **values, CFIndex numValues) { CFAssert2(0 <= numValues, __kCFLogAssertion, "%s(): numValues (%d) cannot be less than zero", __PRETTY_FUNCTION__, numValues); UInt32 flags = __kCFArrayImmutable; __CFBitfieldSetValue(flags, 31, 2, 0); __CFBitfieldSetValue(flags, 3, 2, __kCFArrayHasCFTypeCallBacks); UInt32 size = __CFArrayGetSizeOfType(flags) - sizeof(CFRuntimeBase); size += numValues * sizeof(struct __CFArrayBucket); struct __CFArray *memory = (struct __CFArray*)_CFRuntimeCreateInstance(allocator, __kCFArrayTypeID, size, NULL); if (NULL == memory) { return NULL; } __CFBitfieldSetValue(memory->_base._cfinfo[CF_INFO_BITS], 6, 0, flags); __CFArraySetCount(memory, numValues); memmove(__CFArrayGetBucketsPtr(memory), values, sizeof(void *) * numValues); if (__CFOASafe) __CFSetLastAllocationEventName(memory, "CFArray (immutable)"); return (CFArrayRef)memory; }