]> git.saurik.com Git - apple/cf.git/blame - CFArray.c
CF-550.19.tar.gz
[apple/cf.git] / CFArray.c
CommitLineData
9ce05555 1/*
e588f561 2 * Copyright (c) 2010 Apple Inc. All rights reserved.
9ce05555
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
9ce05555
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
f64f9b69 23
9ce05555 24/* CFArray.c
cf7d2af9 25 Copyright (c) 1998-2009, Apple Inc. All rights reserved.
9ce05555
A
26 Responsibility: Christopher Kane
27*/
28
29#include <CoreFoundation/CFArray.h>
30#include "CFStorage.h"
cf7d2af9 31#include <CoreFoundation/CFPriv.h>
9ce05555
A
32#include "CFInternal.h"
33#include <string.h>
cf7d2af9
A
34#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
35#include <libkern/OSAtomic.h>
36#endif
9ce05555 37
bd5b749c
A
38__private_extern__ void _CFStorageSetWeak(CFStorageRef storage);
39
9ce05555
A
40const CFArrayCallBacks kCFTypeArrayCallBacks = {0, __CFTypeCollectionRetain, __CFTypeCollectionRelease, CFCopyDescription, CFEqual};
41static const CFArrayCallBacks __kCFNullArrayCallBacks = {0, NULL, NULL, NULL, NULL};
42
43struct __CFArrayBucket {
44 const void *_item;
45};
46
9ce05555 47enum {
d8925383 48 __CF_MAX_BUCKETS_PER_DEQUE = 262140
9ce05555
A
49};
50
51CF_INLINE CFIndex __CFArrayDequeRoundUpCapacity(CFIndex capacity) {
52 if (capacity < 4) return 4;
bd5b749c 53 return __CFMin((1 << flsl(capacity)), __CF_MAX_BUCKETS_PER_DEQUE);
9ce05555
A
54}
55
56struct __CFArrayDeque {
d8925383
A
57 uint32_t _leftIdx;
58 uint32_t _capacity;
59 int32_t _bias;
bd5b749c
A
60#if __LP64__
61 uint32_t _pad; // GC: pointers must be 8-byte aligned for the collector to find them.
62#endif
9ce05555
A
63 /* struct __CFArrayBucket buckets follow here */
64};
65
d8925383
A
66struct __CFArray {
67 CFRuntimeBase _base;
68 CFIndex _count; /* number of objects */
bd5b749c 69 CFIndex _mutations;
cf7d2af9 70 int32_t _mutInProgress;
bd5b749c 71 void *_store; /* can be NULL when MutableDeque */
d8925383
A
72};
73
9ce05555
A
74/* Flag bits */
75enum { /* Bits 0-1 */
76 __kCFArrayImmutable = 0,
bd5b749c
A
77 __kCFArrayDeque = 2,
78 __kCFArrayStorage = 3
9ce05555
A
79};
80
81enum { /* Bits 2-3 */
82 __kCFArrayHasNullCallBacks = 0,
83 __kCFArrayHasCFTypeCallBacks = 1,
84 __kCFArrayHasCustomCallBacks = 3 /* callbacks are at end of header */
85};
86
bd5b749c
A
87/*
88 Bits 4 & 5 are reserved for GC use.
89 Bit 4, if set, indicates that the array is weak.
90 Bit 5 marks whether finalization has occured and, thus, whether to continue to do special retain/release processing of elements.
91 */
d8925383 92
bd5b749c
A
93CF_INLINE bool isStrongMemory(CFTypeRef collection) {
94 return __CFBitfieldGetValue(((const CFRuntimeBase *)collection)->_cfinfo[CF_INFO_BITS], 4, 4) == 0;
d8925383
A
95}
96
bd5b749c
A
97CF_INLINE bool isWeakMemory(CFTypeRef collection) {
98 return __CFBitfieldGetValue(((const CFRuntimeBase *)collection)->_cfinfo[CF_INFO_BITS], 4, 4) != 0;
d8925383
A
99}
100
bd5b749c
A
101CF_INLINE bool hasBeenFinalized(CFTypeRef collection) {
102 return __CFBitfieldGetValue(((const CFRuntimeBase *)collection)->_cfinfo[CF_INFO_BITS], 5, 5) != 0;
103}
104
105CF_INLINE void markFinalized(CFTypeRef collection) {
106 __CFBitfieldSetValue(((CFRuntimeBase *)collection)->_cfinfo[CF_INFO_BITS], 5, 5, 1);
107}
d8925383 108
9ce05555 109CF_INLINE CFIndex __CFArrayGetType(CFArrayRef array) {
bd5b749c 110 return __CFBitfieldGetValue(((const CFRuntimeBase *)array)->_cfinfo[CF_INFO_BITS], 1, 0);
9ce05555
A
111}
112
113CF_INLINE CFIndex __CFArrayGetSizeOfType(CFIndex t) {
114 CFIndex size = 0;
bd5b749c 115 size += sizeof(struct __CFArray);
9ce05555
A
116 if (__CFBitfieldGetValue(t, 3, 2) == __kCFArrayHasCustomCallBacks) {
117 size += sizeof(CFArrayCallBacks);
118 }
119 return size;
120}
121
122CF_INLINE CFIndex __CFArrayGetCount(CFArrayRef array) {
bd5b749c 123 return array->_count;
9ce05555
A
124}
125
126CF_INLINE void __CFArraySetCount(CFArrayRef array, CFIndex v) {
bd5b749c 127 ((struct __CFArray *)array)->_count = v;
9ce05555
A
128}
129
bd5b749c 130/* Only applies to immutable and mutable-deque-using arrays;
d8925383 131 * Returns the bucket holding the left-most real value in the latter case. */
9ce05555
A
132CF_INLINE struct __CFArrayBucket *__CFArrayGetBucketsPtr(CFArrayRef array) {
133 switch (__CFArrayGetType(array)) {
134 case __kCFArrayImmutable:
bd5b749c
A
135 return (struct __CFArrayBucket *)((uint8_t *)array + __CFArrayGetSizeOfType(((CFRuntimeBase *)array)->_cfinfo[CF_INFO_BITS]));
136 case __kCFArrayDeque: {
137 struct __CFArrayDeque *deque = (struct __CFArrayDeque *)array->_store;
9ce05555
A
138 return (struct __CFArrayBucket *)((uint8_t *)deque + sizeof(struct __CFArrayDeque) + deque->_leftIdx * sizeof(struct __CFArrayBucket));
139 }
140 }
141 return NULL;
142}
143
144/* This shouldn't be called if the array count is 0. */
145CF_INLINE struct __CFArrayBucket *__CFArrayGetBucketAtIndex(CFArrayRef array, CFIndex idx) {
146 switch (__CFArrayGetType(array)) {
147 case __kCFArrayImmutable:
bd5b749c 148 case __kCFArrayDeque:
9ce05555 149 return __CFArrayGetBucketsPtr(array) + idx;
bd5b749c
A
150 case __kCFArrayStorage: {
151 CFStorageRef store = (CFStorageRef)array->_store;
9ce05555
A
152 return (struct __CFArrayBucket *)CFStorageGetValueAtIndex(store, idx, NULL);
153 }
154 }
155 return NULL;
156}
157
158CF_INLINE CFArrayCallBacks *__CFArrayGetCallBacks(CFArrayRef array) {
159 CFArrayCallBacks *result = NULL;
bd5b749c 160 switch (__CFBitfieldGetValue(((const CFRuntimeBase *)array)->_cfinfo[CF_INFO_BITS], 3, 2)) {
9ce05555
A
161 case __kCFArrayHasNullCallBacks:
162 return (CFArrayCallBacks *)&__kCFNullArrayCallBacks;
163 case __kCFArrayHasCFTypeCallBacks:
164 return (CFArrayCallBacks *)&kCFTypeArrayCallBacks;
165 case __kCFArrayHasCustomCallBacks:
166 break;
167 }
168 switch (__CFArrayGetType(array)) {
169 case __kCFArrayImmutable:
bd5b749c 170 result = (CFArrayCallBacks *)((uint8_t *)array + sizeof(struct __CFArray));
9ce05555 171 break;
bd5b749c
A
172 case __kCFArrayDeque:
173 case __kCFArrayStorage:
174 result = (CFArrayCallBacks *)((uint8_t *)array + sizeof(struct __CFArray));
9ce05555
A
175 break;
176 }
177 return result;
178}
179
180CF_INLINE bool __CFArrayCallBacksMatchNull(const CFArrayCallBacks *c) {
181 return (NULL == c ||
182 (c->retain == __kCFNullArrayCallBacks.retain &&
183 c->release == __kCFNullArrayCallBacks.release &&
184 c->copyDescription == __kCFNullArrayCallBacks.copyDescription &&
185 c->equal == __kCFNullArrayCallBacks.equal));
186}
187
188CF_INLINE bool __CFArrayCallBacksMatchCFType(const CFArrayCallBacks *c) {
189 return (&kCFTypeArrayCallBacks == c ||
190 (c->retain == kCFTypeArrayCallBacks.retain &&
191 c->release == kCFTypeArrayCallBacks.release &&
192 c->copyDescription == kCFTypeArrayCallBacks.copyDescription &&
193 c->equal == kCFTypeArrayCallBacks.equal));
194}
195
cf7d2af9
A
196#if 0
197#define CHECK_FOR_MUTATION(A) do { if ((A)->_mutInProgress) CFLog(3, CFSTR("*** %s: function called while the array (%p) is being mutated in this or another thread"), __PRETTY_FUNCTION__, (A)); } while (0)
198#define BEGIN_MUTATION(A) do { OSAtomicAdd32Barrier(1, &((struct __CFArray *)(A))->_mutInProgress); } while (0)
199#define END_MUTATION(A) do { OSAtomicAdd32Barrier(-1, &((struct __CFArray *)(A))->_mutInProgress); } while (0)
200#else
201#define CHECK_FOR_MUTATION(A) do { } while (0)
202#define BEGIN_MUTATION(A) do { } while (0)
203#define END_MUTATION(A) do { } while (0)
204#endif
205
9ce05555
A
206struct _releaseContext {
207 void (*release)(CFAllocatorRef, const void *);
208 CFAllocatorRef allocator;
209};
210
211static void __CFArrayStorageRelease(const void *itemptr, void *context) {
212 struct _releaseContext *rc = (struct _releaseContext *)context;
213 INVOKE_CALLBACK2(rc->release, rc->allocator, *(const void **)itemptr);
d8925383 214 *(const void **)itemptr = NULL; // GC: clear item to break strong reference.
9ce05555
A
215}
216
217static void __CFArrayReleaseValues(CFArrayRef array, CFRange range, bool releaseStorageIfPossible) {
218 const CFArrayCallBacks *cb = __CFArrayGetCallBacks(array);
219 CFAllocatorRef allocator;
220 CFIndex idx;
221 switch (__CFArrayGetType(array)) {
222 case __kCFArrayImmutable:
bd5b749c
A
223 if (NULL != cb->release && 0 < range.length && !hasBeenFinalized(array)) {
224 // if we've been finalized then we know that
225 // 1) we're using the standard callback on GC memory
226 // 2) the slots don't' need to be zeroed
9ce05555
A
227 struct __CFArrayBucket *buckets = __CFArrayGetBucketsPtr(array);
228 allocator = __CFGetAllocator(array);
229 for (idx = 0; idx < range.length; idx++) {
230 INVOKE_CALLBACK2(cb->release, allocator, buckets[idx + range.location]._item);
d8925383 231 buckets[idx + range.location]._item = NULL; // GC: break strong reference.
9ce05555
A
232 }
233 }
234 break;
bd5b749c
A
235 case __kCFArrayDeque: {
236 struct __CFArrayDeque *deque = (struct __CFArrayDeque *)array->_store;
237 if (0 < range.length && NULL != deque && !hasBeenFinalized(array)) {
9ce05555 238 struct __CFArrayBucket *buckets = __CFArrayGetBucketsPtr(array);
d8925383
A
239 if (NULL != cb->release) {
240 allocator = __CFGetAllocator(array);
241 for (idx = 0; idx < range.length; idx++) {
242 INVOKE_CALLBACK2(cb->release, allocator, buckets[idx + range.location]._item);
243 buckets[idx + range.location]._item = NULL; // GC: break strong reference.
244 }
245 } else {
246 for (idx = 0; idx < range.length; idx++) {
247 buckets[idx + range.location]._item = NULL; // GC: break strong reference.
248 }
9ce05555
A
249 }
250 }
251 if (releaseStorageIfPossible && 0 == range.location && __CFArrayGetCount(array) == range.length) {
252 allocator = __CFGetAllocator(array);
d8925383 253 if (NULL != deque) _CFAllocatorDeallocateGC(allocator, deque);
bd5b749c
A
254 __CFArraySetCount(array, 0); // GC: _count == 0 ==> _store == NULL.
255 ((struct __CFArray *)array)->_store = NULL;
9ce05555
A
256 }
257 break;
258 }
bd5b749c
A
259 case __kCFArrayStorage: {
260 CFStorageRef store = (CFStorageRef)array->_store;
261 if (NULL != cb->release && 0 < range.length && !hasBeenFinalized(array)) {
9ce05555
A
262 struct _releaseContext context;
263 allocator = __CFGetAllocator(array);
264 context.release = cb->release;
265 context.allocator = allocator;
266 CFStorageApplyFunction(store, range, __CFArrayStorageRelease, &context);
267 }
268 if (releaseStorageIfPossible && 0 == range.location && __CFArrayGetCount(array) == range.length) {
bd5b749c
A
269 _CFReleaseGC(store);
270 __CFArraySetCount(array, 0); // GC: _count == 0 ==> _store == NULL.
271 ((struct __CFArray *)array)->_store = NULL;
272 __CFBitfieldSetValue(((CFRuntimeBase *)array)->_cfinfo[CF_INFO_BITS], 1, 0, __kCFArrayDeque);
9ce05555
A
273 }
274 break;
275 }
276 }
277}
278
9ce05555 279#if defined(DEBUG)
bd5b749c 280CF_INLINE void __CFArrayValidateRange(CFArrayRef array, CFRange range, const char *func) {
9ce05555
A
281 CFAssert3(0 <= range.location && range.location <= CFArrayGetCount(array), __kCFLogAssertion, "%s(): range.location index (%d) out of bounds (0, %d)", func, range.location, CFArrayGetCount(array));
282 CFAssert2(0 <= range.length, __kCFLogAssertion, "%s(): range.length (%d) cannot be less than zero", func, range.length);
283 CFAssert3(range.location + range.length <= CFArrayGetCount(array), __kCFLogAssertion, "%s(): ending index (%d) out of bounds (0, %d)", func, range.location + range.length, CFArrayGetCount(array));
9ce05555 284}
bd5b749c
A
285#else
286#define __CFArrayValidateRange(a,r,f)
287#endif
9ce05555 288
bd5b749c 289static Boolean __CFArrayEqual(CFTypeRef cf1, CFTypeRef cf2) {
9ce05555
A
290 CFArrayRef array1 = (CFArrayRef)cf1;
291 CFArrayRef array2 = (CFArrayRef)cf2;
292 const CFArrayCallBacks *cb1, *cb2;
293 CFIndex idx, cnt;
294 if (array1 == array2) return true;
295 cnt = __CFArrayGetCount(array1);
296 if (cnt != __CFArrayGetCount(array2)) return false;
297 cb1 = __CFArrayGetCallBacks(array1);
298 cb2 = __CFArrayGetCallBacks(array2);
299 if (cb1->equal != cb2->equal) return false;
300 if (0 == cnt) return true; /* after function comparison! */
301 for (idx = 0; idx < cnt; idx++) {
302 const void *val1 = __CFArrayGetBucketAtIndex(array1, idx)->_item;
303 const void *val2 = __CFArrayGetBucketAtIndex(array2, idx)->_item;
bd5b749c
A
304 if (val1 != val2) {
305 if (NULL == cb1->equal) return false;
306 if (!INVOKE_CALLBACK2(cb1->equal, val1, val2)) return false;
307 }
9ce05555
A
308 }
309 return true;
310}
311
312static CFHashCode __CFArrayHash(CFTypeRef cf) {
313 CFArrayRef array = (CFArrayRef)cf;
314 return __CFArrayGetCount(array);
315}
316
317static CFStringRef __CFArrayCopyDescription(CFTypeRef cf) {
318 CFArrayRef array = (CFArrayRef)cf;
319 CFMutableStringRef result;
320 const CFArrayCallBacks *cb;
321 CFAllocatorRef allocator;
322 CFIndex idx, cnt;
323 cnt = __CFArrayGetCount(array);
324 allocator = CFGetAllocator(array);
325 result = CFStringCreateMutable(allocator, 0);
326 switch (__CFArrayGetType(array)) {
327 case __kCFArrayImmutable:
cf7d2af9 328 CFStringAppendFormat(result, NULL, CFSTR("<CFArray %p [%p]>{type = immutable, count = %u, values = (%s"), cf, allocator, cnt, cnt ? "\n" : "");
9ce05555 329 break;
bd5b749c 330 case __kCFArrayDeque:
cf7d2af9 331 CFStringAppendFormat(result, NULL, CFSTR("<CFArray %p [%p]>{type = mutable-small, count = %u, values = (%s"), cf, allocator, cnt, cnt ? "\n" : "");
9ce05555 332 break;
bd5b749c 333 case __kCFArrayStorage:
cf7d2af9 334 CFStringAppendFormat(result, NULL, CFSTR("<CFArray %p [%p]>{type = mutable-large, count = %u, values = (%s"), cf, allocator, cnt, cnt ? "\n" : "");
9ce05555
A
335 break;
336 }
337 cb = __CFArrayGetCallBacks(array);
338 for (idx = 0; idx < cnt; idx++) {
339 CFStringRef desc = NULL;
340 const void *val = __CFArrayGetBucketAtIndex(array, idx)->_item;
341 if (NULL != cb->copyDescription) {
342 desc = (CFStringRef)INVOKE_CALLBACK1(cb->copyDescription, val);
343 }
344 if (NULL != desc) {
345 CFStringAppendFormat(result, NULL, CFSTR("\t%u : %@\n"), idx, desc);
346 CFRelease(desc);
347 } else {
348 CFStringAppendFormat(result, NULL, CFSTR("\t%u : <%p>\n"), idx, val);
349 }
350 }
351 CFStringAppend(result, CFSTR(")}"));
352 return result;
353}
354
bd5b749c 355
9ce05555
A
356static void __CFArrayDeallocate(CFTypeRef cf) {
357 CFArrayRef array = (CFArrayRef)cf;
cf7d2af9 358 BEGIN_MUTATION(array);
d8925383
A
359 // Under GC, keep contents alive when we know we can, either standard callbacks or NULL
360 // if (__CFBitfieldGetValue(cf->info, 5, 4)) return; // bits only ever set under GC
361 CFAllocatorRef allocator = __CFGetAllocator(array);
362 if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) {
bd5b749c 363 // XXX_PCB keep array intact during finalization.
d8925383 364 const CFArrayCallBacks *cb = __CFArrayGetCallBacks(array);
cf7d2af9
A
365 if (cb->retain == NULL && cb->release == NULL) {
366 END_MUTATION(array);
bd5b749c 367 return;
cf7d2af9 368 }
bd5b749c
A
369 if (cb == &kCFTypeArrayCallBacks || cb->release == kCFTypeArrayCallBacks.release) {
370 markFinalized(cf);
cf7d2af9
A
371 for (CFIndex idx = 0; idx < __CFArrayGetCount(array); idx++) {
372 const void *item = __CFArrayGetBucketAtIndex(array, 0 + idx)->_item;
373 kCFTypeArrayCallBacks.release(kCFAllocatorSystemDefault, item);
374 }
375 END_MUTATION(array);
bd5b749c
A
376 return;
377 }
d8925383 378 }
9ce05555 379 __CFArrayReleaseValues(array, CFRangeMake(0, __CFArrayGetCount(array)), true);
cf7d2af9 380 END_MUTATION(array);
9ce05555
A
381}
382
383static CFTypeID __kCFArrayTypeID = _kCFRuntimeNotATypeID;
384
385static const CFRuntimeClass __CFArrayClass = {
d8925383 386 _kCFRuntimeScannedObject,
9ce05555
A
387 "CFArray",
388 NULL, // init
389 NULL, // copy
390 __CFArrayDeallocate,
bd5b749c 391 __CFArrayEqual,
9ce05555
A
392 __CFArrayHash,
393 NULL, //
394 __CFArrayCopyDescription
395};
396
397__private_extern__ void __CFArrayInitialize(void) {
398 __kCFArrayTypeID = _CFRuntimeRegisterClass(&__CFArrayClass);
399}
400
401CFTypeID CFArrayGetTypeID(void) {
402 return __kCFArrayTypeID;
403}
404
405static CFArrayRef __CFArrayInit(CFAllocatorRef allocator, UInt32 flags, CFIndex capacity, const CFArrayCallBacks *callBacks) {
bd5b749c 406 struct __CFArray *memory;
9ce05555
A
407 UInt32 size;
408 __CFBitfieldSetValue(flags, 31, 2, 0);
d8925383
A
409 if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) {
410 if (!callBacks || (callBacks->retain == NULL && callBacks->release == NULL)) {
411 __CFBitfieldSetValue(flags, 4, 4, 1); // setWeak
412 }
d8925383 413 }
9ce05555
A
414 if (__CFArrayCallBacksMatchNull(callBacks)) {
415 __CFBitfieldSetValue(flags, 3, 2, __kCFArrayHasNullCallBacks);
416 } else if (__CFArrayCallBacksMatchCFType(callBacks)) {
417 __CFBitfieldSetValue(flags, 3, 2, __kCFArrayHasCFTypeCallBacks);
418 } else {
419 __CFBitfieldSetValue(flags, 3, 2, __kCFArrayHasCustomCallBacks);
420 }
421 size = __CFArrayGetSizeOfType(flags) - sizeof(CFRuntimeBase);
422 switch (__CFBitfieldGetValue(flags, 1, 0)) {
423 case __kCFArrayImmutable:
9ce05555
A
424 size += capacity * sizeof(struct __CFArrayBucket);
425 break;
bd5b749c
A
426 case __kCFArrayDeque:
427 case __kCFArrayStorage:
9ce05555
A
428 break;
429 }
bd5b749c 430 memory = (struct __CFArray*)_CFRuntimeCreateInstance(allocator, __kCFArrayTypeID, size, NULL);
9ce05555
A
431 if (NULL == memory) {
432 return NULL;
433 }
bd5b749c 434 __CFBitfieldSetValue(memory->_base._cfinfo[CF_INFO_BITS], 6, 0, flags);
9ce05555
A
435 __CFArraySetCount((CFArrayRef)memory, 0);
436 switch (__CFBitfieldGetValue(flags, 1, 0)) {
437 case __kCFArrayImmutable:
bd5b749c 438 if (isWeakMemory(memory)) { // if weak, don't scan
cf7d2af9 439 auto_zone_set_unscanned(auto_zone(), memory);
d8925383 440 }
9ce05555
A
441 if (__CFOASafe) __CFSetLastAllocationEventName(memory, "CFArray (immutable)");
442 break;
bd5b749c
A
443 case __kCFArrayDeque:
444 case __kCFArrayStorage:
9ce05555 445 if (__CFOASafe) __CFSetLastAllocationEventName(memory, "CFArray (mutable-variable)");
bd5b749c 446 ((struct __CFArray *)memory)->_mutations = 1;
cf7d2af9 447 ((struct __CFArray *)memory)->_mutInProgress = 0;
bd5b749c 448 ((struct __CFArray*)memory)->_store = NULL;
9ce05555
A
449 break;
450 }
451 if (__kCFArrayHasCustomCallBacks == __CFBitfieldGetValue(flags, 3, 2)) {
d8925383
A
452 CFArrayCallBacks *cb = (CFArrayCallBacks *)__CFArrayGetCallBacks((CFArrayRef)memory);
453 *cb = *callBacks;
9ce05555
A
454 FAULT_CALLBACK((void **)&(cb->retain));
455 FAULT_CALLBACK((void **)&(cb->release));
456 FAULT_CALLBACK((void **)&(cb->copyDescription));
457 FAULT_CALLBACK((void **)&(cb->equal));
458 }
459 return (CFArrayRef)memory;
460}
461
462CFArrayRef CFArrayCreate(CFAllocatorRef allocator, const void **values, CFIndex numValues, const CFArrayCallBacks *callBacks) {
463 CFArrayRef result;
464 const CFArrayCallBacks *cb;
465 struct __CFArrayBucket *buckets;
d8925383
A
466 CFAllocatorRef bucketsAllocator;
467 void* bucketsBase;
9ce05555
A
468 CFIndex idx;
469 CFAssert2(0 <= numValues, __kCFLogAssertion, "%s(): numValues (%d) cannot be less than zero", __PRETTY_FUNCTION__, numValues);
470 result = __CFArrayInit(allocator, __kCFArrayImmutable, numValues, callBacks);
471 cb = __CFArrayGetCallBacks(result);
472 buckets = __CFArrayGetBucketsPtr(result);
d8925383 473 bucketsAllocator = isStrongMemory(result) ? allocator : kCFAllocatorNull;
cf7d2af9 474 bucketsBase = CF_IS_COLLECTABLE_ALLOCATOR(bucketsAllocator) ? (void *)auto_zone_base_pointer(auto_zone(), buckets) : NULL;
bd5b749c
A
475 if (NULL != cb->retain) {
476 for (idx = 0; idx < numValues; idx++) {
cf7d2af9 477 __CFAssignWithWriteBarrier((void **)&buckets->_item, (void *)INVOKE_CALLBACK2(cb->retain, allocator, *values));
bd5b749c
A
478 values++;
479 buckets++;
480 }
481 }
482 else {
483 for (idx = 0; idx < numValues; idx++) {
cf7d2af9 484 __CFAssignWithWriteBarrier((void **)&buckets->_item, (void *)*values);
bd5b749c
A
485 values++;
486 buckets++;
487 }
9ce05555
A
488 }
489 __CFArraySetCount(result, numValues);
490 return result;
491}
492
493CFMutableArrayRef CFArrayCreateMutable(CFAllocatorRef allocator, CFIndex capacity, const CFArrayCallBacks *callBacks) {
494 CFAssert2(0 <= capacity, __kCFLogAssertion, "%s(): capacity (%d) cannot be less than zero", __PRETTY_FUNCTION__, capacity);
bd5b749c
A
495 CFAssert2(capacity <= LONG_MAX / sizeof(void *), __kCFLogAssertion, "%s(): capacity (%d) is too large for this architecture", __PRETTY_FUNCTION__, capacity);
496 return (CFMutableArrayRef)__CFArrayInit(allocator, __kCFArrayDeque, capacity, callBacks);
9ce05555
A
497}
498
9ce05555
A
499CFArrayRef CFArrayCreateCopy(CFAllocatorRef allocator, CFArrayRef array) {
500 CFArrayRef result;
501 const CFArrayCallBacks *cb;
502 struct __CFArrayBucket *buckets;
d8925383
A
503 CFAllocatorRef bucketsAllocator;
504 void* bucketsBase;
9ce05555
A
505 CFIndex numValues = CFArrayGetCount(array);
506 CFIndex idx;
d8925383
A
507 if (CF_IS_OBJC(__kCFArrayTypeID, array)) {
508 cb = &kCFTypeArrayCallBacks;
509 } else {
510 cb = __CFArrayGetCallBacks(array);
d8925383 511 }
9ce05555 512 result = __CFArrayInit(allocator, __kCFArrayImmutable, numValues, cb);
d8925383 513 cb = __CFArrayGetCallBacks(result); // GC: use the new array's callbacks so we don't leak.
9ce05555 514 buckets = __CFArrayGetBucketsPtr(result);
d8925383 515 bucketsAllocator = isStrongMemory(result) ? allocator : kCFAllocatorNull;
cf7d2af9 516 bucketsBase = CF_IS_COLLECTABLE_ALLOCATOR(bucketsAllocator) ? (void *)auto_zone_base_pointer(auto_zone(), buckets) : NULL;
9ce05555
A
517 for (idx = 0; idx < numValues; idx++) {
518 const void *value = CFArrayGetValueAtIndex(array, idx);
519 if (NULL != cb->retain) {
520 value = (void *)INVOKE_CALLBACK2(cb->retain, allocator, value);
521 }
cf7d2af9 522 __CFAssignWithWriteBarrier((void **)&buckets->_item, (void *)value);
9ce05555
A
523 buckets++;
524 }
525 __CFArraySetCount(result, numValues);
526 return result;
527}
528
529CFMutableArrayRef CFArrayCreateMutableCopy(CFAllocatorRef allocator, CFIndex capacity, CFArrayRef array) {
530 CFMutableArrayRef result;
531 const CFArrayCallBacks *cb;
532 CFIndex idx, numValues = CFArrayGetCount(array);
533 UInt32 flags;
d8925383
A
534 if (CF_IS_OBJC(__kCFArrayTypeID, array)) {
535 cb = &kCFTypeArrayCallBacks;
536 }
537 else {
538 cb = __CFArrayGetCallBacks(array);
d8925383 539 }
bd5b749c 540 flags = __kCFArrayDeque;
9ce05555
A
541 result = (CFMutableArrayRef)__CFArrayInit(allocator, flags, capacity, cb);
542 if (0 == capacity) _CFArraySetCapacity(result, numValues);
543 for (idx = 0; idx < numValues; idx++) {
544 const void *value = CFArrayGetValueAtIndex(array, idx);
545 CFArrayAppendValue(result, value);
546 }
547 return result;
548}
549
550CFIndex CFArrayGetCount(CFArrayRef array) {
551 CF_OBJC_FUNCDISPATCH0(__kCFArrayTypeID, CFIndex, array, "count");
552 __CFGenericValidateType(array, __kCFArrayTypeID);
cf7d2af9 553 CHECK_FOR_MUTATION(array);
9ce05555
A
554 return __CFArrayGetCount(array);
555}
556
bd5b749c 557
9ce05555
A
558CFIndex CFArrayGetCountOfValue(CFArrayRef array, CFRange range, const void *value) {
559 const CFArrayCallBacks *cb;
560 CFIndex idx, count = 0;
561// CF: this ignores range
cf7d2af9 562 CF_OBJC_FUNCDISPATCH1(__kCFArrayTypeID, CFIndex, array, "_cfcountOccurrences:", value);
9ce05555
A
563 __CFGenericValidateType(array, __kCFArrayTypeID);
564 __CFArrayValidateRange(array, range, __PRETTY_FUNCTION__);
cf7d2af9 565 CHECK_FOR_MUTATION(array);
9ce05555
A
566 cb = __CFArrayGetCallBacks(array);
567 for (idx = 0; idx < range.length; idx++) {
568 const void *item = __CFArrayGetBucketAtIndex(array, range.location + idx)->_item;
569 if (value == item || (cb->equal && INVOKE_CALLBACK2(cb->equal, value, item))) {
570 count++;
571 }
572 }
573 return count;
574}
575
576Boolean CFArrayContainsValue(CFArrayRef array, CFRange range, const void *value) {
9ce05555
A
577 CFIndex idx;
578 CF_OBJC_FUNCDISPATCH2(__kCFArrayTypeID, char, array, "containsObject:inRange:", value, range);
9ce05555
A
579 __CFGenericValidateType(array, __kCFArrayTypeID);
580 __CFArrayValidateRange(array, range, __PRETTY_FUNCTION__);
cf7d2af9
A
581 CHECK_FOR_MUTATION(array);
582 const CFArrayCallBacks *cb = __CFArrayGetCallBacks(array);
9ce05555
A
583 for (idx = 0; idx < range.length; idx++) {
584 const void *item = __CFArrayGetBucketAtIndex(array, range.location + idx)->_item;
cf7d2af9 585 if (value == item || (cb->equal && INVOKE_CALLBACK2(cb->equal, value, item))) {
9ce05555
A
586 return true;
587 }
588 }
589 return false;
590}
591
592const void *CFArrayGetValueAtIndex(CFArrayRef array, CFIndex idx) {
593 CF_OBJC_FUNCDISPATCH1(__kCFArrayTypeID, void *, array, "objectAtIndex:", idx);
594 __CFGenericValidateType(array, __kCFArrayTypeID);
595 CFAssert2(0 <= idx && idx < __CFArrayGetCount(array), __kCFLogAssertion, "%s(): index (%d) out of bounds", __PRETTY_FUNCTION__, idx);
cf7d2af9 596 CHECK_FOR_MUTATION(array);
9ce05555
A
597 return __CFArrayGetBucketAtIndex(array, idx)->_item;
598}
599
600// This is for use by NSCFArray; it avoids ObjC dispatch, and checks for out of bounds
601const void *_CFArrayCheckAndGetValueAtIndex(CFArrayRef array, CFIndex idx) {
cf7d2af9 602 CHECK_FOR_MUTATION(array);
9ce05555
A
603 if (0 <= idx && idx < __CFArrayGetCount(array)) return __CFArrayGetBucketAtIndex(array, idx)->_item;
604 return (void *)(-1);
605}
606
607
608void CFArrayGetValues(CFArrayRef array, CFRange range, const void **values) {
bd5b749c 609 CF_OBJC_FUNCDISPATCH2(__kCFArrayTypeID, void, array, "getObjects:range:", values, range);
9ce05555
A
610 __CFGenericValidateType(array, __kCFArrayTypeID);
611 __CFArrayValidateRange(array, range, __PRETTY_FUNCTION__);
612 CFAssert1(NULL != values, __kCFLogAssertion, "%s(): pointer to values may not be NULL", __PRETTY_FUNCTION__);
cf7d2af9 613 CHECK_FOR_MUTATION(array);
9ce05555
A
614 if (0 < range.length) {
615 switch (__CFArrayGetType(array)) {
616 case __kCFArrayImmutable:
bd5b749c 617 case __kCFArrayDeque:
cf7d2af9 618 objc_memmove_collectable(values, __CFArrayGetBucketsPtr(array) + range.location, range.length * sizeof(struct __CFArrayBucket));
9ce05555 619 break;
bd5b749c
A
620 case __kCFArrayStorage: {
621 CFStorageRef store = (CFStorageRef)array->_store;
9ce05555
A
622 CFStorageGetValues(store, range, values);
623 break;
624 }
625 }
626 }
627}
628
bd5b749c 629
cf7d2af9
A
630CF_EXPORT unsigned long _CFArrayFastEnumeration(CFArrayRef array, struct __objcFastEnumerationStateEquivalent *state, void *stackbuffer, unsigned long count) {
631 CHECK_FOR_MUTATION(array);
bd5b749c
A
632 if (array->_count == 0) return 0;
633 enum { ATSTART = 0, ATEND = 1 };
634 switch (__CFArrayGetType(array)) {
635 case __kCFArrayImmutable:
636 if (state->state == ATSTART) { /* first time */
637 static const unsigned long const_mu = 1;
638 state->state = ATEND;
639 state->mutationsPtr = (unsigned long *)&const_mu;
640 state->itemsPtr = (unsigned long *)__CFArrayGetBucketsPtr(array);
641 return array->_count;
642 }
643 return 0;
644 case __kCFArrayDeque:
645 if (state->state == ATSTART) { /* first time */
646 state->state = ATEND;
647 state->mutationsPtr = (unsigned long *)&array->_mutations;
648 state->itemsPtr = (unsigned long *)__CFArrayGetBucketsPtr(array);
649 return array->_count;
650 }
651 return 0;
652 case __kCFArrayStorage:
653 state->mutationsPtr = (unsigned long *)&array->_mutations;
654 return _CFStorageFastEnumeration((CFStorageRef)array->_store, state, stackbuffer, count);
655 }
656 return 0;
657}
658
659
9ce05555
A
660void CFArrayApplyFunction(CFArrayRef array, CFRange range, CFArrayApplierFunction applier, void *context) {
661 CFIndex idx;
662 FAULT_CALLBACK((void **)&(applier));
cf7d2af9 663 CF_OBJC_FUNCDISPATCH2(__kCFArrayTypeID, void, array, "_cfapply:context:", applier, context);
9ce05555
A
664 __CFGenericValidateType(array, __kCFArrayTypeID);
665 __CFArrayValidateRange(array, range, __PRETTY_FUNCTION__);
666 CFAssert1(NULL != applier, __kCFLogAssertion, "%s(): pointer to applier function may not be NULL", __PRETTY_FUNCTION__);
cf7d2af9 667 CHECK_FOR_MUTATION(array);
9ce05555
A
668 for (idx = 0; idx < range.length; idx++) {
669 const void *item = __CFArrayGetBucketAtIndex(array, range.location + idx)->_item;
670 INVOKE_CALLBACK2(applier, item, context);
671 }
672}
673
674CFIndex CFArrayGetFirstIndexOfValue(CFArrayRef array, CFRange range, const void *value) {
675 const CFArrayCallBacks *cb;
676 CFIndex idx;
677 CF_OBJC_FUNCDISPATCH2(__kCFArrayTypeID, CFIndex, array, "_cfindexOfObject:inRange:", value, range);
9ce05555
A
678 __CFGenericValidateType(array, __kCFArrayTypeID);
679 __CFArrayValidateRange(array, range, __PRETTY_FUNCTION__);
cf7d2af9 680 CHECK_FOR_MUTATION(array);
9ce05555
A
681 cb = __CFArrayGetCallBacks(array);
682 for (idx = 0; idx < range.length; idx++) {
683 const void *item = __CFArrayGetBucketAtIndex(array, range.location + idx)->_item;
684 if (value == item || (cb->equal && INVOKE_CALLBACK2(cb->equal, value, item)))
685 return idx + range.location;
686 }
687 return kCFNotFound;
688}
689
690CFIndex CFArrayGetLastIndexOfValue(CFArrayRef array, CFRange range, const void *value) {
691 const CFArrayCallBacks *cb;
692 CFIndex idx;
693 CF_OBJC_FUNCDISPATCH2(__kCFArrayTypeID, CFIndex, array, "_cflastIndexOfObject:inRange:", value, range);
9ce05555
A
694 __CFGenericValidateType(array, __kCFArrayTypeID);
695 __CFArrayValidateRange(array, range, __PRETTY_FUNCTION__);
cf7d2af9 696 CHECK_FOR_MUTATION(array);
9ce05555
A
697 cb = __CFArrayGetCallBacks(array);
698 for (idx = range.length; idx--;) {
699 const void *item = __CFArrayGetBucketAtIndex(array, range.location + idx)->_item;
700 if (value == item || (cb->equal && INVOKE_CALLBACK2(cb->equal, value, item)))
701 return idx + range.location;
702 }
703 return kCFNotFound;
704}
705
706void CFArrayAppendValue(CFMutableArrayRef array, const void *value) {
707 CF_OBJC_FUNCDISPATCH1(__kCFArrayTypeID, void, array, "addObject:", value);
708 __CFGenericValidateType(array, __kCFArrayTypeID);
709 CFAssert1(__CFArrayGetType(array) != __kCFArrayImmutable, __kCFLogAssertion, "%s(): array is immutable", __PRETTY_FUNCTION__);
cf7d2af9 710 CHECK_FOR_MUTATION(array);
9ce05555
A
711 _CFArrayReplaceValues(array, CFRangeMake(__CFArrayGetCount(array), 0), &value, 1);
712}
713
714void CFArraySetValueAtIndex(CFMutableArrayRef array, CFIndex idx, const void *value) {
715 CF_OBJC_FUNCDISPATCH2(__kCFArrayTypeID, void, array, "setObject:atIndex:", value, idx);
716 __CFGenericValidateType(array, __kCFArrayTypeID);
717 CFAssert1(__CFArrayGetType(array) != __kCFArrayImmutable, __kCFLogAssertion, "%s(): array is immutable", __PRETTY_FUNCTION__);
718 CFAssert2(0 <= idx && idx <= __CFArrayGetCount(array), __kCFLogAssertion, "%s(): index (%d) out of bounds", __PRETTY_FUNCTION__, idx);
cf7d2af9 719 CHECK_FOR_MUTATION(array);
9ce05555
A
720 if (idx == __CFArrayGetCount(array)) {
721 _CFArrayReplaceValues(array, CFRangeMake(idx, 0), &value, 1);
722 } else {
cf7d2af9 723 BEGIN_MUTATION(array);
9ce05555
A
724 const void *old_value;
725 const CFArrayCallBacks *cb = __CFArrayGetCallBacks(array);
726 CFAllocatorRef allocator = __CFGetAllocator(array);
d8925383 727 struct __CFArrayBucket *bucket = __CFArrayGetBucketAtIndex(array, idx);
bd5b749c 728 if (NULL != cb->retain && !hasBeenFinalized(array)) {
9ce05555
A
729 value = (void *)INVOKE_CALLBACK2(cb->retain, allocator, value);
730 }
d8925383 731 old_value = bucket->_item;
cf7d2af9 732 __CFAssignWithWriteBarrier((void **)&bucket->_item, (void *)value); // GC: handles deque/CFStorage cases.
bd5b749c 733 if (NULL != cb->release && !hasBeenFinalized(array)) {
9ce05555
A
734 INVOKE_CALLBACK2(cb->release, allocator, old_value);
735 }
bd5b749c 736 array->_mutations++;
cf7d2af9 737 END_MUTATION(array);
9ce05555
A
738 }
739}
740
741void CFArrayInsertValueAtIndex(CFMutableArrayRef array, CFIndex idx, const void *value) {
742 CF_OBJC_FUNCDISPATCH2(__kCFArrayTypeID, void, array, "insertObject:atIndex:", value, idx);
743 __CFGenericValidateType(array, __kCFArrayTypeID);
744 CFAssert1(__CFArrayGetType(array) != __kCFArrayImmutable, __kCFLogAssertion, "%s(): array is immutable", __PRETTY_FUNCTION__);
745 CFAssert2(0 <= idx && idx <= __CFArrayGetCount(array), __kCFLogAssertion, "%s(): index (%d) out of bounds", __PRETTY_FUNCTION__, idx);
cf7d2af9 746 CHECK_FOR_MUTATION(array);
9ce05555
A
747 _CFArrayReplaceValues(array, CFRangeMake(idx, 0), &value, 1);
748}
749
750void CFArrayExchangeValuesAtIndices(CFMutableArrayRef array, CFIndex idx1, CFIndex idx2) {
751 const void *tmp;
d8925383
A
752 struct __CFArrayBucket *bucket1, *bucket2;
753 CFAllocatorRef bucketsAllocator;
cf7d2af9 754 CF_OBJC_FUNCDISPATCH2(__kCFArrayTypeID, void, array, "_cfexchange::", idx1, idx2);
9ce05555
A
755 __CFGenericValidateType(array, __kCFArrayTypeID);
756 CFAssert2(0 <= idx1 && idx1 < __CFArrayGetCount(array), __kCFLogAssertion, "%s(): index #1 (%d) out of bounds", __PRETTY_FUNCTION__, idx1);
757 CFAssert2(0 <= idx2 && idx2 < __CFArrayGetCount(array), __kCFLogAssertion, "%s(): index #2 (%d) out of bounds", __PRETTY_FUNCTION__, idx2);
758 CFAssert1(__CFArrayGetType(array) != __kCFArrayImmutable, __kCFLogAssertion, "%s(): array is immutable", __PRETTY_FUNCTION__);
cf7d2af9
A
759 CHECK_FOR_MUTATION(array);
760 BEGIN_MUTATION(array);
d8925383
A
761 bucket1 = __CFArrayGetBucketAtIndex(array, idx1);
762 bucket2 = __CFArrayGetBucketAtIndex(array, idx2);
763 tmp = bucket1->_item;
764 bucketsAllocator = isStrongMemory(array) ? __CFGetAllocator(array) : kCFAllocatorNull;
bd5b749c 765 // XXX these aren't needed.
cf7d2af9
A
766 __CFAssignWithWriteBarrier((void **)&bucket1->_item, (void *)bucket2->_item);
767 __CFAssignWithWriteBarrier((void **)&bucket2->_item, (void *)tmp);
bd5b749c 768 array->_mutations++;
cf7d2af9 769 END_MUTATION(array);
9ce05555
A
770}
771
772void CFArrayRemoveValueAtIndex(CFMutableArrayRef array, CFIndex idx) {
773 CF_OBJC_FUNCDISPATCH1(__kCFArrayTypeID, void, array, "removeObjectAtIndex:", idx);
774 __CFGenericValidateType(array, __kCFArrayTypeID);
775 CFAssert1(__CFArrayGetType(array) != __kCFArrayImmutable, __kCFLogAssertion, "%s(): array is immutable", __PRETTY_FUNCTION__);
776 CFAssert2(0 <= idx && idx < __CFArrayGetCount(array), __kCFLogAssertion, "%s(): index (%d) out of bounds", __PRETTY_FUNCTION__, idx);
cf7d2af9 777 CHECK_FOR_MUTATION(array);
9ce05555
A
778 _CFArrayReplaceValues(array, CFRangeMake(idx, 1), NULL, 0);
779}
780
781void CFArrayRemoveAllValues(CFMutableArrayRef array) {
782 CF_OBJC_FUNCDISPATCH0(__kCFArrayTypeID, void, array, "removeAllObjects");
783 __CFGenericValidateType(array, __kCFArrayTypeID);
784 CFAssert1(__CFArrayGetType(array) != __kCFArrayImmutable, __kCFLogAssertion, "%s(): array is immutable", __PRETTY_FUNCTION__);
cf7d2af9
A
785 CHECK_FOR_MUTATION(array);
786 BEGIN_MUTATION(array);
9ce05555
A
787 __CFArrayReleaseValues(array, CFRangeMake(0, __CFArrayGetCount(array)), true);
788 __CFArraySetCount(array, 0);
bd5b749c 789 array->_mutations++;
cf7d2af9 790 END_MUTATION(array);
9ce05555
A
791}
792
793static void __CFArrayConvertDequeToStore(CFMutableArrayRef array) {
bd5b749c 794 struct __CFArrayDeque *deque = (struct __CFArrayDeque *)array->_store;
9ce05555
A
795 struct __CFArrayBucket *raw_buckets = (struct __CFArrayBucket *)((uint8_t *)deque + sizeof(struct __CFArrayDeque));
796 CFStorageRef store;
cf7d2af9 797 CFIndex count = __CFArrayGetCount(array);
d8925383 798 CFAllocatorRef allocator = __CFGetAllocator(array);
cf7d2af9
A
799 Boolean collectableMemory = CF_IS_COLLECTABLE_ALLOCATOR(allocator);
800 if (collectableMemory) auto_zone_retain(auto_zone(), deque);
801 store = CFStorageCreate(allocator, sizeof(const void *));
9ce05555 802 if (__CFOASafe) __CFSetLastAllocationEventName(store, "CFArray (store-storage)");
cf7d2af9
A
803 __CFAssignWithWriteBarrier((void **)&array->_store, (void *)store);
804 CFMakeCollectable(store); // GC: now safe to unroot the store.
9ce05555
A
805 CFStorageInsertValues(store, CFRangeMake(0, count));
806 CFStorageReplaceValues(store, CFRangeMake(0, count), raw_buckets + deque->_leftIdx);
cf7d2af9 807 CFAllocatorDeallocate(__CFGetAllocator(array), deque);
bd5b749c 808 __CFBitfieldSetValue(((CFRuntimeBase *)array)->_cfinfo[CF_INFO_BITS], 1, 0, __kCFArrayStorage);
9ce05555
A
809}
810
811static void __CFArrayConvertStoreToDeque(CFMutableArrayRef array) {
bd5b749c 812 CFStorageRef store = (CFStorageRef)array->_store;
9ce05555
A
813 struct __CFArrayDeque *deque;
814 struct __CFArrayBucket *raw_buckets;
815 CFIndex count = CFStorageGetCount(store);// storage, not array, has correct count at this point
816 // do not resize down to a completely tight deque
817 CFIndex capacity = __CFArrayDequeRoundUpCapacity(count + 6);
818 CFIndex size = sizeof(struct __CFArrayDeque) + capacity * sizeof(struct __CFArrayBucket);
d8925383 819 CFAllocatorRef allocator = __CFGetAllocator(array);
cf7d2af9
A
820 Boolean collectableMemory = CF_IS_COLLECTABLE_ALLOCATOR(allocator);
821 if (collectableMemory) CFRetain(store); // GC: need to root the CFStorage
822 deque = (struct __CFArrayDeque *)CFAllocatorAllocate(allocator, size, isStrongMemory(array) ? __kCFAllocatorGCScannedMemory : 0);
9ce05555
A
823 if (__CFOASafe) __CFSetLastAllocationEventName(deque, "CFArray (store-deque)");
824 deque->_leftIdx = (capacity - count) / 2;
825 deque->_capacity = capacity;
d8925383 826 deque->_bias = 0;
cf7d2af9
A
827 __CFAssignWithWriteBarrier((void **)&array->_store, (void *)deque);
828 if (collectableMemory) auto_zone_release(auto_zone(), deque);
9ce05555
A
829 raw_buckets = (struct __CFArrayBucket *)((uint8_t *)deque + sizeof(struct __CFArrayDeque));
830 CFStorageGetValues(store, CFRangeMake(0, count), raw_buckets + deque->_leftIdx);
cf7d2af9 831 CFRelease(store);
bd5b749c 832 __CFBitfieldSetValue(((CFRuntimeBase *)array)->_cfinfo[CF_INFO_BITS], 1, 0, __kCFArrayDeque);
9ce05555
A
833}
834
835// may move deque storage, as it may need to grow deque
836static void __CFArrayRepositionDequeRegions(CFMutableArrayRef array, CFRange range, CFIndex newCount) {
837 // newCount elements are going to replace the range, and the result will fit in the deque
bd5b749c 838 struct __CFArrayDeque *deque = (struct __CFArrayDeque *)array->_store;
9ce05555
A
839 struct __CFArrayBucket *buckets;
840 CFIndex cnt, futureCnt, numNewElems;
841 CFIndex L, A, B, C, R;
842
843 buckets = (struct __CFArrayBucket *)((uint8_t *)deque + sizeof(struct __CFArrayDeque));
844 cnt = __CFArrayGetCount(array);
845 futureCnt = cnt - range.length + newCount;
846
847 L = deque->_leftIdx; // length of region to left of deque
848 A = range.location; // length of region in deque to left of replaced range
849 B = range.length; // length of replaced range
850 C = cnt - B - A; // length of region in deque to right of replaced range
851 R = deque->_capacity - cnt - L; // length of region to right of deque
852 numNewElems = newCount - B;
853
d8925383
A
854 CFIndex wiggle = deque->_capacity >> 17;
855 if (wiggle < 4) wiggle = 4;
bd5b749c 856 if (deque->_capacity < (uint32_t)futureCnt || (cnt < futureCnt && L + R < wiggle)) {
d8925383
A
857 // must be inserting or space is tight, reallocate and re-center everything
858 CFIndex capacity = __CFArrayDequeRoundUpCapacity(futureCnt + wiggle);
9ce05555
A
859 CFIndex size = sizeof(struct __CFArrayDeque) + capacity * sizeof(struct __CFArrayBucket);
860 CFAllocatorRef allocator = __CFGetAllocator(array);
cf7d2af9 861 struct __CFArrayDeque *newDeque = (struct __CFArrayDeque *)CFAllocatorAllocate(allocator, size, isStrongMemory(array) ? __kCFAllocatorGCScannedMemory : 0);
9ce05555
A
862 if (__CFOASafe) __CFSetLastAllocationEventName(newDeque, "CFArray (store-deque)");
863 struct __CFArrayBucket *newBuckets = (struct __CFArrayBucket *)((uint8_t *)newDeque + sizeof(struct __CFArrayDeque));
864 CFIndex oldL = L;
865 CFIndex newL = (capacity - futureCnt) / 2;
866 CFIndex oldC0 = oldL + A + B;
867 CFIndex newC0 = newL + A + newCount;
868 newDeque->_leftIdx = newL;
869 newDeque->_capacity = capacity;
bd5b749c 870 newDeque->_bias = 0;
cf7d2af9
A
871 if (0 < A) objc_memmove_collectable(newBuckets + newL, buckets + oldL, A * sizeof(struct __CFArrayBucket));
872 if (0 < C) objc_memmove_collectable(newBuckets + newC0, buckets + oldC0, C * sizeof(struct __CFArrayBucket));
d8925383 873 if (deque) _CFAllocatorDeallocateGC(allocator, deque);
cf7d2af9
A
874 __CFAssignWithWriteBarrier((void **)&array->_store, (void *)newDeque);
875 if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) auto_zone_release(auto_zone(), newDeque);
9ce05555
A
876 return;
877 }
878
879 if ((numNewElems < 0 && C < A) || (numNewElems <= R && C < A)) { // move C
880 // deleting: C is smaller
881 // inserting: C is smaller and R has room
882 CFIndex oldC0 = L + A + B;
883 CFIndex newC0 = L + A + newCount;
cf7d2af9 884 if (0 < C) objc_memmove_collectable(buckets + newC0, buckets + oldC0, C * sizeof(struct __CFArrayBucket));
d8925383 885 // GrP GC: zero-out newly exposed space on the right, if any
cf7d2af9 886 if (oldC0 > newC0) memset(buckets + newC0 + C, 0, (oldC0 - newC0) * sizeof(struct __CFArrayBucket));
9ce05555
A
887 } else if ((numNewElems < 0) || (numNewElems <= L && A <= C)) { // move A
888 // deleting: A is smaller or equal (covers remaining delete cases)
889 // inserting: A is smaller and L has room
890 CFIndex oldL = L;
891 CFIndex newL = L - numNewElems;
892 deque->_leftIdx = newL;
cf7d2af9 893 if (0 < A) objc_memmove_collectable(buckets + newL, buckets + oldL, A * sizeof(struct __CFArrayBucket));
d8925383 894 // GrP GC: zero-out newly exposed space on the left, if any
cf7d2af9 895 if (newL > oldL) memset(buckets + oldL, 0, (newL - oldL) * sizeof(struct __CFArrayBucket));
9ce05555
A
896 } else {
897 // now, must be inserting, and either:
898 // A<=C, but L doesn't have room (R might have, but don't care)
899 // C<A, but R doesn't have room (L might have, but don't care)
900 // re-center everything
901 CFIndex oldL = L;
902 CFIndex newL = (L + R - numNewElems) / 2;
d8925383
A
903 CFIndex oldBias = deque->_bias;
904 deque->_bias = (newL < oldL) ? -1 : 1;
905 if (oldBias < 0) {
906 newL = newL - newL / 2;
907 } else if (0 < oldBias) {
908 newL = newL + newL / 2;
909 }
9ce05555
A
910 CFIndex oldC0 = oldL + A + B;
911 CFIndex newC0 = newL + A + newCount;
912 deque->_leftIdx = newL;
913 if (newL < oldL) {
cf7d2af9
A
914 if (0 < A) objc_memmove_collectable(buckets + newL, buckets + oldL, A * sizeof(struct __CFArrayBucket));
915 if (0 < C) objc_memmove_collectable(buckets + newC0, buckets + oldC0, C * sizeof(struct __CFArrayBucket));
d8925383 916 // GrP GC: zero-out newly exposed space on the right, if any
cf7d2af9 917 if (oldC0 > newC0) memset(buckets + newC0 + C, 0, (oldC0 - newC0) * sizeof(struct __CFArrayBucket));
9ce05555 918 } else {
cf7d2af9
A
919 if (0 < C) objc_memmove_collectable(buckets + newC0, buckets + oldC0, C * sizeof(struct __CFArrayBucket));
920 if (0 < A) objc_memmove_collectable(buckets + newL, buckets + oldL, A * sizeof(struct __CFArrayBucket));
d8925383 921 // GrP GC: zero-out newly exposed space on the left, if any
cf7d2af9 922 if (newL > oldL) memset(buckets + oldL, 0, (newL - oldL) * sizeof(struct __CFArrayBucket));
9ce05555
A
923 }
924 }
925}
926
bd5b749c
A
927static void __CFArrayHandleOutOfMemory(CFTypeRef obj, CFIndex numBytes) {
928 CFStringRef msg = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("Attempt to allocate %ld bytes for CFArray failed"), numBytes);
cf7d2af9 929 {
bd5b749c
A
930 CFLog(kCFLogLevelCritical, CFSTR("%@"), msg);
931 HALT;
932 }
933 CFRelease(msg);
934}
935
9ce05555
A
936// This function is for Foundation's benefit; no one else should use it.
937void _CFArraySetCapacity(CFMutableArrayRef array, CFIndex cap) {
938 if (CF_IS_OBJC(__kCFArrayTypeID, array)) return;
9ce05555 939 __CFGenericValidateType(array, __kCFArrayTypeID);
bd5b749c 940 CFAssert1(__CFArrayGetType(array) != __kCFArrayImmutable, __kCFLogAssertion, "%s(): array is immutable", __PRETTY_FUNCTION__);
9ce05555 941 CFAssert3(__CFArrayGetCount(array) <= cap, __kCFLogAssertion, "%s(): desired capacity (%d) is less than count (%d)", __PRETTY_FUNCTION__, cap, __CFArrayGetCount(array));
cf7d2af9
A
942 CHECK_FOR_MUTATION(array);
943 BEGIN_MUTATION(array);
9ce05555
A
944 // Currently, attempting to set the capacity of an array which is the CFStorage
945 // variant, or set the capacity larger than __CF_MAX_BUCKETS_PER_DEQUE, has no
946 // effect. The primary purpose of this API is to help avoid a bunch of the
947 // resizes at the small capacities 4, 8, 16, etc.
bd5b749c
A
948 if (__CFArrayGetType(array) == __kCFArrayDeque) {
949 struct __CFArrayDeque *deque = (struct __CFArrayDeque *)array->_store;
9ce05555
A
950 CFIndex capacity = __CFArrayDequeRoundUpCapacity(cap);
951 CFIndex size = sizeof(struct __CFArrayDeque) + capacity * sizeof(struct __CFArrayBucket);
d8925383 952 CFAllocatorRef allocator = __CFGetAllocator(array);
cf7d2af9 953 Boolean collectableMemory = CF_IS_COLLECTABLE_ALLOCATOR(allocator);
9ce05555 954 if (NULL == deque) {
cf7d2af9 955 deque = (struct __CFArrayDeque *)CFAllocatorAllocate(allocator, size, isStrongMemory(array) ? __kCFAllocatorGCScannedMemory : 0);
bd5b749c 956 if (NULL == deque) __CFArrayHandleOutOfMemory(array, size);
9ce05555
A
957 if (__CFOASafe) __CFSetLastAllocationEventName(deque, "CFArray (store-deque)");
958 deque->_leftIdx = capacity / 2;
959 } else {
bd5b749c
A
960 struct __CFArrayDeque *olddeque = deque;
961 CFIndex oldcap = deque->_capacity;
cf7d2af9 962 deque = (struct __CFArrayDeque *)CFAllocatorAllocate(allocator, size, isStrongMemory(array) ? __kCFAllocatorGCScannedMemory : 0);
bd5b749c 963 if (NULL == deque) __CFArrayHandleOutOfMemory(array, size);
cf7d2af9 964 objc_memmove_collectable(deque, olddeque, sizeof(struct __CFArrayDeque) + oldcap * sizeof(struct __CFArrayBucket));
bd5b749c 965 _CFAllocatorDeallocateGC(allocator, olddeque);
9ce05555
A
966 if (__CFOASafe) __CFSetLastAllocationEventName(deque, "CFArray (store-deque)");
967 }
968 deque->_capacity = capacity;
d8925383 969 deque->_bias = 0;
cf7d2af9
A
970 __CFAssignWithWriteBarrier((void **)&array->_store, (void *)deque);
971 if (collectableMemory) auto_zone_release(auto_zone(), deque);
9ce05555 972 }
cf7d2af9 973 END_MUTATION(array);
9ce05555
A
974}
975
9ce05555
A
976
977void CFArrayReplaceValues(CFMutableArrayRef array, CFRange range, const void **newValues, CFIndex newCount) {
978 CF_OBJC_FUNCDISPATCH3(__kCFArrayTypeID, void, array, "replaceObjectsInRange:withObjects:count:", range, (void **)newValues, newCount);
9ce05555
A
979 __CFGenericValidateType(array, __kCFArrayTypeID);
980 __CFArrayValidateRange(array, range, __PRETTY_FUNCTION__);
9ce05555
A
981 CFAssert1(__CFArrayGetType(array) != __kCFArrayImmutable, __kCFLogAssertion, "%s(): array is immutable", __PRETTY_FUNCTION__);
982 CFAssert2(0 <= newCount, __kCFLogAssertion, "%s(): newCount (%d) cannot be less than zero", __PRETTY_FUNCTION__, newCount);
cf7d2af9 983 CHECK_FOR_MUTATION(array);
9ce05555
A
984 return _CFArrayReplaceValues(array, range, newValues, newCount);
985}
986
987// This function does no ObjC dispatch or argument checking;
988// It should only be called from places where that dispatch and check has already been done, or NSCFArray
989void _CFArrayReplaceValues(CFMutableArrayRef array, CFRange range, const void **newValues, CFIndex newCount) {
cf7d2af9
A
990 CHECK_FOR_MUTATION(array);
991 BEGIN_MUTATION(array);
9ce05555
A
992 const CFArrayCallBacks *cb;
993 CFAllocatorRef allocator;
994 CFIndex idx, cnt, futureCnt;
995 const void **newv, *buffer[256];
996 cnt = __CFArrayGetCount(array);
997 futureCnt = cnt - range.length + newCount;
9ce05555
A
998 CFAssert1(newCount <= futureCnt, __kCFLogAssertion, "%s(): internal error 1", __PRETTY_FUNCTION__);
999 cb = __CFArrayGetCallBacks(array);
1000 allocator = __CFGetAllocator(array);
cf7d2af9 1001
9ce05555 1002 /* Retain new values if needed, possibly allocating a temporary buffer for them */
bd5b749c
A
1003 if (NULL != cb->retain && !hasBeenFinalized(array)) {
1004 newv = (newCount <= 256) ? (const void **)buffer : (const void **)CFAllocatorAllocate(allocator, newCount * sizeof(void *), 0); // GC OK
9ce05555
A
1005 if (newv != buffer && __CFOASafe) __CFSetLastAllocationEventName(newv, "CFArray (temp)");
1006 for (idx = 0; idx < newCount; idx++) {
1007 newv[idx] = (void *)INVOKE_CALLBACK2(cb->retain, allocator, (void *)newValues[idx]);
1008 }
1009 } else {
1010 newv = newValues;
1011 }
bd5b749c
A
1012 array->_mutations++;
1013
9ce05555
A
1014 /* Now, there are three regions of interest, each of which may be empty:
1015 * A: the region from index 0 to one less than the range.location
1016 * B: the region of the range
1017 * C: the region from range.location + range.length to the end
1018 * Note that index 0 is not necessarily at the lowest-address edge
1019 * of the available storage. The values in region B need to get
1020 * released, and the values in regions A and C (depending) need
1021 * to get shifted if the number of new values is different from
1022 * the length of the range being replaced.
1023 */
9ce05555
A
1024 if (0 < range.length) {
1025 __CFArrayReleaseValues(array, range, false);
1026 }
1027 // region B elements are now "dead"
bd5b749c
A
1028 if (__kCFArrayStorage == __CFArrayGetType(array)) {
1029 CFStorageRef store = (CFStorageRef)array->_store;
9ce05555 1030 // reposition regions A and C for new region B elements in gap
d8925383
A
1031 if (range.length < newCount) {
1032 CFStorageInsertValues(store, CFRangeMake(range.location + range.length, newCount - range.length));
1033 } else if (newCount < range.length) {
1034 CFStorageDeleteValues(store, CFRangeMake(range.location + newCount, range.length - newCount));
1035 }
9ce05555
A
1036 if (futureCnt <= __CF_MAX_BUCKETS_PER_DEQUE / 2) {
1037 __CFArrayConvertStoreToDeque(array);
1038 }
bd5b749c 1039 } else if (NULL == array->_store) {
9ce05555 1040 if (__CF_MAX_BUCKETS_PER_DEQUE <= futureCnt) {
cf7d2af9 1041 CFStorageRef store = CFStorageCreate(allocator, sizeof(const void *));
d8925383 1042 if (! isStrongMemory(array)) _CFStorageSetWeak(store);
9ce05555 1043 if (__CFOASafe) __CFSetLastAllocationEventName(store, "CFArray (store-storage)");
cf7d2af9
A
1044 __CFAssignWithWriteBarrier((void **)&array->_store, (void *)store);
1045 CFMakeCollectable(store);
d8925383 1046 CFStorageInsertValues(store, CFRangeMake(0, newCount));
bd5b749c 1047 __CFBitfieldSetValue(((CFRuntimeBase *)array)->_cfinfo[CF_INFO_BITS], 1, 0, __kCFArrayStorage);
9ce05555
A
1048 } else if (0 <= futureCnt) {
1049 struct __CFArrayDeque *deque;
1050 CFIndex capacity = __CFArrayDequeRoundUpCapacity(futureCnt);
1051 CFIndex size = sizeof(struct __CFArrayDeque) + capacity * sizeof(struct __CFArrayBucket);
cf7d2af9 1052 deque = (struct __CFArrayDeque *)CFAllocatorAllocate(allocator, size, isStrongMemory(array) ? __kCFAllocatorGCScannedMemory : 0);
9ce05555
A
1053 if (__CFOASafe) __CFSetLastAllocationEventName(deque, "CFArray (store-deque)");
1054 deque->_leftIdx = (capacity - newCount) / 2;
1055 deque->_capacity = capacity;
d8925383 1056 deque->_bias = 0;
cf7d2af9
A
1057 __CFAssignWithWriteBarrier((void **)&array->_store, (void *)deque);
1058 if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) auto_zone_release(auto_zone(), deque); // GC: now safe to unroot the array body.
9ce05555
A
1059 }
1060 } else { // Deque
1061 // reposition regions A and C for new region B elements in gap
1062 if (__CF_MAX_BUCKETS_PER_DEQUE <= futureCnt) {
1063 CFStorageRef store;
1064 __CFArrayConvertDequeToStore(array);
bd5b749c 1065 store = (CFStorageRef)array->_store;
9ce05555
A
1066 if (range.length < newCount) {
1067 CFStorageInsertValues(store, CFRangeMake(range.location + range.length, newCount - range.length));
1068 } else if (newCount < range.length) { // this won't happen, but is here for completeness
1069 CFStorageDeleteValues(store, CFRangeMake(range.location + newCount, range.length - newCount));
1070 }
1071 } else if (range.length != newCount) {
1072 __CFArrayRepositionDequeRegions(array, range, newCount);
1073 }
1074 }
1075 // copy in new region B elements
1076 if (0 < newCount) {
bd5b749c
A
1077 if (__kCFArrayStorage == __CFArrayGetType(array)) {
1078 CFStorageRef store = (CFStorageRef)array->_store;
9ce05555
A
1079 CFStorageReplaceValues(store, CFRangeMake(range.location, newCount), newv);
1080 } else { // Deque
bd5b749c 1081 struct __CFArrayDeque *deque = (struct __CFArrayDeque *)array->_store;
9ce05555 1082 struct __CFArrayBucket *raw_buckets = (struct __CFArrayBucket *)((uint8_t *)deque + sizeof(struct __CFArrayDeque));
cf7d2af9 1083 objc_memmove_collectable(raw_buckets + deque->_leftIdx + range.location, newv, newCount * sizeof(struct __CFArrayBucket));
9ce05555
A
1084 }
1085 }
1086 __CFArraySetCount(array, futureCnt);
1087 if (newv != buffer && newv != newValues) CFAllocatorDeallocate(allocator, newv);
cf7d2af9 1088 END_MUTATION(array);
9ce05555
A
1089}
1090
1091struct _acompareContext {
1092 CFComparatorFunction func;
1093 void *context;
1094};
1095
1096static CFComparisonResult __CFArrayCompareValues(const void *v1, const void *v2, struct _acompareContext *context) {
1097 const void **val1 = (const void **)v1;
1098 const void **val2 = (const void **)v2;
1099 return (CFComparisonResult)(INVOKE_CALLBACK3(context->func, *val1, *val2, context->context));
1100}
1101
1102void CFArraySortValues(CFMutableArrayRef array, CFRange range, CFComparatorFunction comparator, void *context) {
1103 FAULT_CALLBACK((void **)&(comparator));
1104 CF_OBJC_FUNCDISPATCH3(__kCFArrayTypeID, void, array, "sortUsingFunction:context:range:", comparator, context, range);
9ce05555
A
1105 __CFGenericValidateType(array, __kCFArrayTypeID);
1106 __CFArrayValidateRange(array, range, __PRETTY_FUNCTION__);
9ce05555
A
1107 CFAssert1(__CFArrayGetType(array) != __kCFArrayImmutable, __kCFLogAssertion, "%s(): array is immutable", __PRETTY_FUNCTION__);
1108 CFAssert1(NULL != comparator, __kCFLogAssertion, "%s(): pointer to comparator function may not be NULL", __PRETTY_FUNCTION__);
cf7d2af9
A
1109 CHECK_FOR_MUTATION(array);
1110 BEGIN_MUTATION(array);
bd5b749c
A
1111 array->_mutations++;
1112
9ce05555
A
1113 if (1 < range.length) {
1114 struct _acompareContext ctx;
d8925383 1115 struct __CFArrayBucket *bucket;
9ce05555
A
1116 ctx.func = comparator;
1117 ctx.context = context;
1118 switch (__CFArrayGetType(array)) {
bd5b749c 1119 case __kCFArrayDeque:
d8925383 1120 bucket = __CFArrayGetBucketsPtr(array) + range.location;
cf7d2af9 1121 CFQSortArray(bucket, range.length, sizeof(void *), (CFComparatorFunction)__CFArrayCompareValues, &ctx);
9ce05555 1122 break;
bd5b749c
A
1123 case __kCFArrayStorage: {
1124 CFStorageRef store = (CFStorageRef)array->_store;
9ce05555 1125 const void **values, *buffer[256];
cf7d2af9 1126 values = (range.length <= 256) ? (const void **)buffer : (const void **)CFAllocatorAllocate(kCFAllocatorSystemDefault, range.length * sizeof(void *), 0); // GC OK
9ce05555
A
1127 if (values != buffer && __CFOASafe) __CFSetLastAllocationEventName(values, "CFArray (temp)");
1128 CFStorageGetValues(store, range, values);
1129 CFQSortArray(values, range.length, sizeof(void *), (CFComparatorFunction)__CFArrayCompareValues, &ctx);
1130 CFStorageReplaceValues(store, range, values);
cf7d2af9 1131 if (values != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, values); // GC OK
9ce05555
A
1132 break;
1133 }
1134 }
1135 }
cf7d2af9 1136 END_MUTATION(array);
9ce05555
A
1137}
1138
1139CFIndex CFArrayBSearchValues(CFArrayRef array, CFRange range, const void *value, CFComparatorFunction comparator, void *context) {
bd5b749c
A
1140 __CFGenericValidateType(array, __kCFArrayTypeID);
1141 __CFArrayValidateRange(array, range, __PRETTY_FUNCTION__);
1142 CFAssert1(NULL != comparator, __kCFLogAssertion, "%s(): pointer to comparator function may not be NULL", __PRETTY_FUNCTION__);
9ce05555 1143 bool isObjC = CF_IS_OBJC(__kCFArrayTypeID, array);
9ce05555 1144 FAULT_CALLBACK((void **)&(comparator));
cf7d2af9 1145 if (!isObjC) CHECK_FOR_MUTATION(array);
bd5b749c 1146 CFIndex idx = 0;
9ce05555 1147 if (range.length <= 0) return range.location;
bd5b749c 1148 if (isObjC || __kCFArrayStorage == __CFArrayGetType(array)) {
9ce05555
A
1149 const void *item;
1150 SInt32 lg;
1151 item = CFArrayGetValueAtIndex(array, range.location + range.length - 1);
1152 if ((CFComparisonResult)(INVOKE_CALLBACK3(comparator, item, value, context)) < 0) {
1153 return range.location + range.length;
1154 }
1155 item = CFArrayGetValueAtIndex(array, range.location);
1156 if ((CFComparisonResult)(INVOKE_CALLBACK3(comparator, value, item, context)) < 0) {
1157 return range.location;
1158 }
bd5b749c 1159 lg = flsl(range.length) - 1; // lg2(range.length)
9ce05555
A
1160 item = CFArrayGetValueAtIndex(array, range.location + -1 + (1 << lg));
1161 idx = range.location + ((CFComparisonResult)(INVOKE_CALLBACK3(comparator, item, value, context)) < 0) ? range.length - (1 << lg) : -1;
1162 while (lg--) {
1163 item = CFArrayGetValueAtIndex(array, range.location + idx + (1 << lg));
1164 if ((CFComparisonResult)(INVOKE_CALLBACK3(comparator, item, value, context)) < 0) {
1165 idx += (1 << lg);
1166 }
1167 }
1168 idx++;
1169 } else {
1170 struct _acompareContext ctx;
1171 ctx.func = comparator;
1172 ctx.context = context;
1173 idx = CFBSearch(&value, sizeof(void *), __CFArrayGetBucketsPtr(array) + range.location, range.length, (CFComparatorFunction)__CFArrayCompareValues, &ctx);
1174 }
1175 return idx + range.location;
1176}
1177
1178void CFArrayAppendArray(CFMutableArrayRef array, CFArrayRef otherArray, CFRange otherRange) {
1179 CFIndex idx;
9ce05555
A
1180 __CFGenericValidateType(array, __kCFArrayTypeID);
1181 __CFGenericValidateType(otherArray, __kCFArrayTypeID);
1182 CFAssert1(__CFArrayGetType(array) != __kCFArrayImmutable, __kCFLogAssertion, "%s(): array is immutable", __PRETTY_FUNCTION__);
1183 __CFArrayValidateRange(otherArray, otherRange, __PRETTY_FUNCTION__);
cf7d2af9 1184 CHECK_FOR_MUTATION(array);
9ce05555
A
1185 for (idx = otherRange.location; idx < otherRange.location + otherRange.length; idx++) {
1186 CFArrayAppendValue(array, CFArrayGetValueAtIndex(otherArray, idx));
1187 }
1188}
cf7d2af9
A
1189
1190// ----====---- ----====---- ----====---- ----====----
1191
1192__private_extern__ Boolean __CFArray6130(CFMutableArrayRef array, CFIndex *p, void **list) {
1193 if (CF_IS_OBJC(__kCFArrayTypeID, array)) return false;
1194 CHECK_FOR_MUTATION(array);
1195 if (__kCFArrayStorage == __CFArrayGetType(array)) {
1196 CFStorageRef store = (CFStorageRef)array->_store;
1197 CFRange range = {0, 0};
1198 void *bytes = NULL;
1199 for (CFIndex idx = 0; idx < __CFArrayGetCount(array); idx++) {
1200 if (range.location + range.length - 1 < idx) {
1201 bytes = CFStorageGetValueAtIndex(store, idx, &range);
1202 }
1203 ((void **)bytes)[idx - range.location] = list[p[idx]];
1204 }
1205 } else if (kCFUseCollectableAllocator) { // Deque
1206 struct __CFArrayDeque *deque = (struct __CFArrayDeque *)array->_store;
1207 struct __CFArrayBucket *raw_buckets = (struct __CFArrayBucket *)((uint8_t *)deque + sizeof(struct __CFArrayDeque)) + deque->_leftIdx;
1208 for (CFIndex idx = 0; idx < __CFArrayGetCount(array); idx++) {
1209 struct __CFArrayBucket *dest = raw_buckets + idx;
1210 objc_memmove_collectable(dest, list + p[idx], sizeof(struct __CFArrayBucket));
1211 }
1212 } else { // Deque
1213 struct __CFArrayDeque *deque = (struct __CFArrayDeque *)array->_store;
1214 struct __CFArrayBucket *raw_buckets = (struct __CFArrayBucket *)((uint8_t *)deque + sizeof(struct __CFArrayDeque)) + deque->_leftIdx;
1215 for (CFIndex idx = 0; idx < __CFArrayGetCount(array); idx++) {
1216 raw_buckets[idx]._item = list[p[idx]];
1217 }
1218 }
1219 return true;
1220}
1221