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; }
const void *CFArrayGetValueAtIndex(CFArrayRef array, CFIndex idx) { CF_OBJC_FUNCDISPATCHV(__kCFArrayTypeID, const void *, (NSArray *)array, objectAtIndex:idx); __CFGenericValidateType(array, __kCFArrayTypeID); CFAssert2(0 <= idx && idx < __CFArrayGetCount(array), __kCFLogAssertion, "%s(): index (%d) out of bounds", __PRETTY_FUNCTION__, idx); CHECK_FOR_MUTATION(array); return __CFArrayGetBucketAtIndex(array, idx)->_item; }
void CFArraySetValueAtIndex(CFMutableArrayRef array, CFIndex idx, const void *value) { CF_OBJC_FUNCDISPATCHV(__kCFArrayTypeID, void, (NSMutableArray *)array, setObject:(id)value atIndex:(NSUInteger)idx); __CFGenericValidateType(array, __kCFArrayTypeID); CFAssert1(__CFArrayGetType(array) != __kCFArrayImmutable, __kCFLogAssertion, "%s(): array is immutable", __PRETTY_FUNCTION__); CFAssert2(0 <= idx && idx <= __CFArrayGetCount(array), __kCFLogAssertion, "%s(): index (%d) out of bounds", __PRETTY_FUNCTION__, idx); CHECK_FOR_MUTATION(array); if (idx == __CFArrayGetCount(array)) { _CFArrayReplaceValues(array, CFRangeMake(idx, 0), &value, 1); } else { BEGIN_MUTATION(array); const void *old_value; const CFArrayCallBacks *cb = __CFArrayGetCallBacks(array); CFAllocatorRef allocator = __CFGetAllocator(array); struct __CFArrayBucket *bucket = __CFArrayGetBucketAtIndex(array, idx); if (NULL != cb->retain && !hasBeenFinalized(array)) { value = (void *)INVOKE_CALLBACK2(cb->retain, allocator, value); } old_value = bucket->_item; __CFAssignWithWriteBarrier((void **)&bucket->_item, (void *)value); // GC: handles deque/CFStorage cases. if (NULL != cb->release && !hasBeenFinalized(array)) { INVOKE_CALLBACK2(cb->release, allocator, old_value); } array->_mutations++; END_MUTATION(array); } }
void CFArrayAppendValue(CFMutableArrayRef array, const void *value) { CF_OBJC_FUNCDISPATCH1(__kCFArrayTypeID, void, array, "addObject:", value); __CFGenericValidateType(array, __kCFArrayTypeID); CFAssert1(__CFArrayGetType(array) != __kCFArrayImmutable, __kCFLogAssertion, "%s(): array is immutable", __PRETTY_FUNCTION__); CHECK_FOR_MUTATION(array); _CFArrayReplaceValues(array, CFRangeMake(__CFArrayGetCount(array), 0), &value, 1); }
void CFArrayRemoveValueAtIndex(CFMutableArrayRef array, CFIndex idx) { CF_OBJC_FUNCDISPATCHV(__kCFArrayTypeID, void, (NSMutableArray *)array, removeObjectAtIndex:(NSUInteger)idx); __CFGenericValidateType(array, __kCFArrayTypeID); CFAssert1(__CFArrayGetType(array) != __kCFArrayImmutable, __kCFLogAssertion, "%s(): array is immutable", __PRETTY_FUNCTION__); CFAssert2(0 <= idx && idx < __CFArrayGetCount(array), __kCFLogAssertion, "%s(): index (%d) out of bounds", __PRETTY_FUNCTION__, idx); CHECK_FOR_MUTATION(array); _CFArrayReplaceValues(array, CFRangeMake(idx, 1), NULL, 0); }
void CFArrayInsertValueAtIndex(CFMutableArrayRef array, CFIndex idx, const void *value) { CF_OBJC_FUNCDISPATCH2(__kCFArrayTypeID, void, array, "insertObject:atIndex:", value, idx); __CFGenericValidateType(array, __kCFArrayTypeID); CFAssert1(__CFArrayGetType(array) != __kCFArrayImmutable, __kCFLogAssertion, "%s(): array is immutable", __PRETTY_FUNCTION__); CFAssert2(0 <= idx && idx <= __CFArrayGetCount(array), __kCFLogAssertion, "%s(): index (%d) out of bounds", __PRETTY_FUNCTION__, idx); CHECK_FOR_MUTATION(array); _CFArrayReplaceValues(array, CFRangeMake(idx, 0), &value, 1); }
void CFArrayReplaceValues(CFMutableArrayRef array, CFRange range, const void **newValues, CFIndex newCount) { CF_OBJC_FUNCDISPATCHV(__kCFArrayTypeID, void, (NSMutableArray *)array, replaceObjectsInRange:NSMakeRange(range.location, range.length) withObjects:(id *)newValues count:(NSUInteger)newCount); __CFGenericValidateType(array, __kCFArrayTypeID); __CFArrayValidateRange(array, range, __PRETTY_FUNCTION__); CFAssert1(__CFArrayGetType(array) != __kCFArrayImmutable, __kCFLogAssertion, "%s(): array is immutable", __PRETTY_FUNCTION__); CFAssert2(0 <= newCount, __kCFLogAssertion, "%s(): newCount (%d) cannot be less than zero", __PRETTY_FUNCTION__, newCount); CHECK_FOR_MUTATION(array); return _CFArrayReplaceValues(array, range, newValues, newCount); }
void CFArrayRemoveAllValues(CFMutableArrayRef array) { CF_OBJC_FUNCDISPATCHV(__kCFArrayTypeID, void, (NSMutableArray *)array, removeAllObjects); __CFGenericValidateType(array, __kCFArrayTypeID); CFAssert1(__CFArrayGetType(array) != __kCFArrayImmutable, __kCFLogAssertion, "%s(): array is immutable", __PRETTY_FUNCTION__); CHECK_FOR_MUTATION(array); BEGIN_MUTATION(array); __CFArrayReleaseValues(array, CFRangeMake(0, __CFArrayGetCount(array)), true); __CFArraySetCount(array, 0); array->_mutations++; END_MUTATION(array); }
void CFArrayApplyFunction(CFArrayRef array, CFRange range, CFArrayApplierFunction applier, void *context) { CFIndex idx; FAULT_CALLBACK((void **)&(applier)); __CFGenericValidateType(array, __kCFArrayTypeID); __CFArrayValidateRange(array, range, __PRETTY_FUNCTION__); CFAssert1(NULL != applier, __kCFLogAssertion, "%s(): pointer to applier function may not be NULL", __PRETTY_FUNCTION__); CHECK_FOR_MUTATION(array); for (idx = 0; idx < range.length; idx++) { const void *item = CFArrayGetValueAtIndex(array, range.location + idx); INVOKE_CALLBACK2(applier, item, context); } }
CFIndex CFArrayGetLastIndexOfValue(CFArrayRef array, CFRange range, const void *value) { CFIndex idx; __CFGenericValidateType(array, __kCFArrayTypeID); __CFArrayValidateRange(array, range, __PRETTY_FUNCTION__); CHECK_FOR_MUTATION(array); const CFArrayCallBacks *cb = CF_IS_OBJC(CFArrayGetTypeID(), array) ? &kCFTypeArrayCallBacks : __CFArrayGetCallBacks(array); for (idx = range.length; idx--;) { const void *item = CFArrayGetValueAtIndex(array, range.location + idx); if (value == item || (cb->equal && INVOKE_CALLBACK2(cb->equal, value, item))) return idx + range.location; } return kCFNotFound; }
Boolean CFArrayContainsValue(CFArrayRef array, CFRange range, const void *value) { CFIndex idx; __CFGenericValidateType(array, __kCFArrayTypeID); __CFArrayValidateRange(array, range, __PRETTY_FUNCTION__); CHECK_FOR_MUTATION(array); const CFArrayCallBacks *cb = CF_IS_OBJC(CFArrayGetTypeID(), array) ? &kCFTypeArrayCallBacks : __CFArrayGetCallBacks(array); for (idx = 0; idx < range.length; idx++) { const void *item = CFArrayGetValueAtIndex(array, range.location + idx); if (value == item || (cb->equal && INVOKE_CALLBACK2(cb->equal, value, item))) { return true; } } return false; }
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; } } }
// NB: AddressBook on the Phone is a fragile flower, so this function cannot do anything // that causes the values to be retained or released. void CFArrayExchangeValuesAtIndices(CFMutableArrayRef array, CFIndex idx1, CFIndex idx2) { const void *tmp; struct __CFArrayBucket *bucket1, *bucket2; CF_OBJC_FUNCDISPATCHV(__kCFArrayTypeID, void, (NSMutableArray *)array, exchangeObjectAtIndex:(NSUInteger)idx1 withObjectAtIndex:(NSUInteger)idx2); __CFGenericValidateType(array, __kCFArrayTypeID); CFAssert2(0 <= idx1 && idx1 < __CFArrayGetCount(array), __kCFLogAssertion, "%s(): index #1 (%d) out of bounds", __PRETTY_FUNCTION__, idx1); CFAssert2(0 <= idx2 && idx2 < __CFArrayGetCount(array), __kCFLogAssertion, "%s(): index #2 (%d) out of bounds", __PRETTY_FUNCTION__, idx2); CFAssert1(__CFArrayGetType(array) != __kCFArrayImmutable, __kCFLogAssertion, "%s(): array is immutable", __PRETTY_FUNCTION__); CHECK_FOR_MUTATION(array); BEGIN_MUTATION(array); bucket1 = __CFArrayGetBucketAtIndex(array, idx1); bucket2 = __CFArrayGetBucketAtIndex(array, idx2); tmp = bucket1->_item; // XXX these aren't needed. __CFAssignWithWriteBarrier((void **)&bucket1->_item, (void *)bucket2->_item); __CFAssignWithWriteBarrier((void **)&bucket2->_item, (void *)tmp); array->_mutations++; END_MUTATION(array); }
// This function is for Foundation's benefit; no one else should use it. void _CFArraySetCapacity(CFMutableArrayRef array, CFIndex cap) { if (CF_IS_OBJC(__kCFArrayTypeID, array)) return; __CFGenericValidateType(array, __kCFArrayTypeID); CFAssert1(__CFArrayGetType(array) != __kCFArrayImmutable, __kCFLogAssertion, "%s(): array is immutable", __PRETTY_FUNCTION__); CFAssert3(__CFArrayGetCount(array) <= cap, __kCFLogAssertion, "%s(): desired capacity (%d) is less than count (%d)", __PRETTY_FUNCTION__, cap, __CFArrayGetCount(array)); CHECK_FOR_MUTATION(array); BEGIN_MUTATION(array); // Currently, attempting to set the capacity of an array which is the CFStorage // variant, or set the capacity larger than __CF_MAX_BUCKETS_PER_DEQUE, has no // effect. The primary purpose of this API is to help avoid a bunch of the // resizes at the small capacities 4, 8, 16, etc. if (__CFArrayGetType(array) == __kCFArrayDeque) { struct __CFArrayDeque *deque = (struct __CFArrayDeque *)array->_store; CFIndex capacity = __CFArrayDequeRoundUpCapacity(cap); CFIndex size = sizeof(struct __CFArrayDeque) + capacity * sizeof(struct __CFArrayBucket); CFAllocatorRef allocator = __CFGetAllocator(array); allocator = _CFConvertAllocatorToGCRefZeroEquivalent(allocator); Boolean collectableMemory = CF_IS_COLLECTABLE_ALLOCATOR(allocator); if (NULL == deque) { deque = (struct __CFArrayDeque *)CFAllocatorAllocate(allocator, size, isStrongMemory(array) ? __kCFAllocatorGCScannedMemory : 0); if (NULL == deque) __CFArrayHandleOutOfMemory(array, size); if (__CFOASafe) __CFSetLastAllocationEventName(deque, "CFArray (store-deque)"); deque->_leftIdx = capacity / 2; } else { struct __CFArrayDeque *olddeque = deque; CFIndex oldcap = deque->_capacity; deque = (struct __CFArrayDeque *)CFAllocatorAllocate(allocator, size, isStrongMemory(array) ? __kCFAllocatorGCScannedMemory : 0); if (NULL == deque) __CFArrayHandleOutOfMemory(array, size); objc_memmove_collectable(deque, olddeque, sizeof(struct __CFArrayDeque) + oldcap * sizeof(struct __CFArrayBucket)); if (!collectableMemory) CFAllocatorDeallocate(allocator, olddeque); if (__CFOASafe) __CFSetLastAllocationEventName(deque, "CFArray (store-deque)"); } deque->_capacity = capacity; __CFAssignWithWriteBarrier((void **)&array->_store, (void *)deque); } END_MUTATION(array); }
// This function does no ObjC dispatch or argument checking; // It should only be called from places where that dispatch and check has already been done, or NSCFArray void _CFArrayReplaceValues(CFMutableArrayRef array, CFRange range, const void **newValues, CFIndex newCount) { CHECK_FOR_MUTATION(array); BEGIN_MUTATION(array); const CFArrayCallBacks *cb; CFIndex idx, cnt, futureCnt; const void **newv, *buffer[256]; cnt = __CFArrayGetCount(array); futureCnt = cnt - range.length + newCount; CFAssert1(newCount <= futureCnt, __kCFLogAssertion, "%s(): internal error 1", __PRETTY_FUNCTION__); cb = __CFArrayGetCallBacks(array); CFAllocatorRef allocator = __CFGetAllocator(array); /* Retain new values if needed, possibly allocating a temporary buffer for them */ if (NULL != cb->retain && !hasBeenFinalized(array)) { newv = (newCount <= 256) ? (const void **)buffer : (const void **)CFAllocatorAllocate(kCFAllocatorSystemDefault, newCount * sizeof(void *), 0); // GC OK if (newv != buffer && __CFOASafe) __CFSetLastAllocationEventName(newv, "CFArray (temp)"); for (idx = 0; idx < newCount; idx++) { newv[idx] = (void *)INVOKE_CALLBACK2(cb->retain, allocator, (void *)newValues[idx]); } } else { newv = newValues; } array->_mutations++; /* Now, there are three regions of interest, each of which may be empty: * A: the region from index 0 to one less than the range.location * B: the region of the range * C: the region from range.location + range.length to the end * Note that index 0 is not necessarily at the lowest-address edge * of the available storage. The values in region B need to get * released, and the values in regions A and C (depending) need * to get shifted if the number of new values is different from * the length of the range being replaced. */ if (0 < range.length) { __CFArrayReleaseValues(array, range, false); } // region B elements are now "dead" if (0) { } else if (NULL == array->_store) { if (0) { } else if (0 <= futureCnt) { struct __CFArrayDeque *deque; CFIndex capacity = __CFArrayDequeRoundUpCapacity(futureCnt); CFIndex size = sizeof(struct __CFArrayDeque) + capacity * sizeof(struct __CFArrayBucket); deque = (struct __CFArrayDeque *)CFAllocatorAllocate(_CFConvertAllocatorToGCRefZeroEquivalent(allocator), size, isStrongMemory(array) ? __kCFAllocatorGCScannedMemory : 0); if (__CFOASafe) __CFSetLastAllocationEventName(deque, "CFArray (store-deque)"); deque->_leftIdx = (capacity - newCount) / 2; deque->_capacity = capacity; __CFAssignWithWriteBarrier((void **)&array->_store, (void *)deque); } } else { // Deque // reposition regions A and C for new region B elements in gap if (0) { } else if (range.length != newCount) { __CFArrayRepositionDequeRegions(array, range, newCount); } } // copy in new region B elements if (0 < newCount) { if (0) { } else { // Deque struct __CFArrayDeque *deque = (struct __CFArrayDeque *)array->_store; struct __CFArrayBucket *raw_buckets = (struct __CFArrayBucket *)((uint8_t *)deque + sizeof(struct __CFArrayDeque)); objc_memmove_collectable(raw_buckets + deque->_leftIdx + range.location, newv, newCount * sizeof(struct __CFArrayBucket)); } } __CFArraySetCount(array, futureCnt); if (newv != buffer && newv != newValues) CFAllocatorDeallocate(kCFAllocatorSystemDefault, newv); END_MUTATION(array); }
CFIndex CFArrayGetCount(CFArrayRef array) { CF_OBJC_FUNCDISPATCHV(__kCFArrayTypeID, CFIndex, (NSArray *)array, count); __CFGenericValidateType(array, __kCFArrayTypeID); CHECK_FOR_MUTATION(array); return __CFArrayGetCount(array); }
// This is for use by NSCFArray; it avoids ObjC dispatch, and checks for out of bounds const void *_CFArrayCheckAndGetValueAtIndex(CFArrayRef array, CFIndex idx) { CHECK_FOR_MUTATION(array); if (0 <= idx && idx < __CFArrayGetCount(array)) return __CFArrayGetBucketAtIndex(array, idx)->_item; return (void *)(-1); }