2 * Copyright (c) 2008 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
24 Copyright 1998-2006, Apple, Inc. All rights reserved.
25 Responsibility: Christopher Kane
26 Machine generated from Notes/HashingCode.template
32 #include <CoreFoundation/CFDictionary.h>
33 #include "CFInternal.h"
34 #include <mach-o/dyld.h>
36 #define CFDictionary 0
40 #define CFDictionary 1
43 const CFDictionaryKeyCallBacks kCFTypeDictionaryKeyCallBacks
= {0, __CFTypeCollectionRetain
, __CFTypeCollectionRelease
, CFCopyDescription
, CFEqual
, CFHash
};
44 const CFDictionaryKeyCallBacks kCFCopyStringDictionaryKeyCallBacks
= {0, __CFStringCollectionCopy
, __CFTypeCollectionRelease
, CFCopyDescription
, CFEqual
, CFHash
};
45 const CFDictionaryValueCallBacks kCFTypeDictionaryValueCallBacks
= {0, __CFTypeCollectionRetain
, __CFTypeCollectionRelease
, CFCopyDescription
, CFEqual
};
46 static const CFDictionaryKeyCallBacks __kCFNullDictionaryKeyCallBacks
= {0, NULL
, NULL
, NULL
, NULL
, NULL
};
47 static const CFDictionaryValueCallBacks __kCFNullDictionaryValueCallBacks
= {0, NULL
, NULL
, NULL
, NULL
};
49 #define CFHashRef CFDictionaryRef
50 #define CFMutableHashRef CFMutableDictionaryRef
51 #define __kCFHashTypeID __kCFDictionaryTypeID
55 const CFDictionaryCallBacks kCFTypeDictionaryCallBacks
= {0, __CFTypeCollectionRetain
, __CFTypeCollectionRelease
, CFCopyDescription
, CFEqual
, CFHash
};
56 const CFDictionaryCallBacks kCFCopyStringDictionaryCallBacks
= {0, __CFStringCollectionCopy
, __CFTypeCollectionRelease
, CFCopyDescription
, CFEqual
, CFHash
};
57 static const CFDictionaryCallBacks __kCFNullDictionaryCallBacks
= {0, NULL
, NULL
, NULL
, NULL
, NULL
};
59 #define CFDictionaryKeyCallBacks CFDictionaryCallBacks
60 #define CFDictionaryValueCallBacks CFDictionaryCallBacks
61 #define kCFTypeDictionaryKeyCallBacks kCFTypeDictionaryCallBacks
62 #define kCFTypeDictionaryValueCallBacks kCFTypeDictionaryCallBacks
63 #define __kCFNullDictionaryKeyCallBacks __kCFNullDictionaryCallBacks
64 #define __kCFNullDictionaryValueCallBacks __kCFNullDictionaryCallBacks
66 #define CFHashRef CFSetRef
67 #define CFMutableHashRef CFMutableSetRef
68 #define __kCFHashTypeID __kCFSetTypeID
72 const CFDictionaryCallBacks kCFTypeDictionaryCallBacks
= {0, __CFTypeCollectionRetain
, __CFTypeCollectionRelease
, CFCopyDescription
, CFEqual
, CFHash
};
73 const CFDictionaryCallBacks kCFCopyStringDictionaryCallBacks
= {0, __CFStringCollectionCopy
, __CFTypeCollectionRelease
, CFCopyDescription
, CFEqual
, CFHash
};
74 static const CFDictionaryCallBacks __kCFNullDictionaryCallBacks
= {0, NULL
, NULL
, NULL
, NULL
, NULL
};
76 #define CFDictionaryKeyCallBacks CFDictionaryCallBacks
77 #define CFDictionaryValueCallBacks CFDictionaryCallBacks
78 #define kCFTypeDictionaryKeyCallBacks kCFTypeDictionaryCallBacks
79 #define kCFTypeDictionaryValueCallBacks kCFTypeDictionaryCallBacks
80 #define __kCFNullDictionaryKeyCallBacks __kCFNullDictionaryCallBacks
81 #define __kCFNullDictionaryValueCallBacks __kCFNullDictionaryCallBacks
83 #define CFHashRef CFBagRef
84 #define CFMutableHashRef CFMutableBagRef
85 #define __kCFHashTypeID __kCFBagTypeID
88 #define GETNEWKEY(newKey, oldKey) \
89 any_t (*kretain)(CFAllocatorRef, any_t, any_pointer_t) = \
90 !hasBeenFinalized(hc) \
91 ? (any_t (*)(CFAllocatorRef,any_t,any_pointer_t))__CFDictionaryGetKeyCallBacks(hc)->retain \
92 : (any_t (*)(CFAllocatorRef,any_t,any_pointer_t))0; \
93 any_t newKey = kretain ? (any_t)INVOKE_CALLBACK3(kretain, allocator, (any_t)key, hc->_context) : (any_t)oldKey
95 #define RELEASEKEY(oldKey) \
96 void (*krelease)(CFAllocatorRef, any_t, any_pointer_t) = \
97 !hasBeenFinalized(hc) \
98 ? (void (*)(CFAllocatorRef,any_t,any_pointer_t))__CFDictionaryGetKeyCallBacks(hc)->release \
99 : (void (*)(CFAllocatorRef,any_t,any_pointer_t))0; \
100 if (krelease) INVOKE_CALLBACK3(krelease, allocator, oldKey, hc->_context)
103 #define GETNEWVALUE(newValue) \
104 any_t (*vretain)(CFAllocatorRef, any_t, any_pointer_t) = \
105 !hasBeenFinalized(hc) \
106 ? (any_t (*)(CFAllocatorRef,any_t,any_pointer_t))__CFDictionaryGetValueCallBacks(hc)->retain \
107 : (any_t (*)(CFAllocatorRef,any_t,any_pointer_t))0; \
108 any_t newValue = vretain ? (any_t)INVOKE_CALLBACK3(vretain, allocator, (any_t)value, hc->_context) : (any_t)value
110 #define RELEASEVALUE(oldValue) \
111 void (*vrelease)(CFAllocatorRef, any_t, any_pointer_t) = \
112 !hasBeenFinalized(hc) \
113 ? (void (*)(CFAllocatorRef,any_t,any_pointer_t))__CFDictionaryGetValueCallBacks(hc)->release \
114 : (void (*)(CFAllocatorRef,any_t,any_pointer_t))0; \
115 if (vrelease) INVOKE_CALLBACK3(vrelease, allocator, oldValue, hc->_context)
119 static void __CFDictionaryHandleOutOfMemory(CFTypeRef obj
, CFIndex numBytes
) {
120 CFStringRef msg
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("Attempt to allocate %ld bytes for NS/CFDictionary failed"), numBytes
);
121 CFBadErrorCallBack cb
= _CFGetOutOfMemoryErrorCallBack();
122 if (NULL
== cb
|| !cb(obj
, CFSTR("NS/CFDictionary"), msg
)) {
123 CFLog(kCFLogLevelCritical
, CFSTR("%@"), msg
);
130 // Max load is 3/4 number of buckets
131 CF_INLINE CFIndex
__CFHashRoundUpCapacity(CFIndex capacity
) {
132 return 3 * ((CFIndex
)1 << (flsl((capacity
- 1) / 3)));
135 // Returns next power of two higher than the capacity
136 // threshold for the given input capacity.
137 CF_INLINE CFIndex
__CFHashNumBucketsForCapacity(CFIndex capacity
) {
138 return 4 * ((CFIndex
)1 << (flsl((capacity
- 1) / 3)));
141 enum { /* Bits 1-0 */
142 __kCFHashImmutable
= 0, /* unchangable and fixed capacity */
143 __kCFHashMutable
= 1, /* changeable and variable capacity */
146 enum { /* Bits 5-4 (value), 3-2 (key) */
147 __kCFHashHasNullCallBacks
= 0,
148 __kCFHashHasCFTypeCallBacks
= 1,
149 __kCFHashHasCustomCallBacks
= 3 /* callbacks are at end of header */
152 // Under GC, we fudge the key/value memory in two ways
153 // First, if we had null callbacks or null for both retain/release, we use unscanned memory and get
154 // standard 'dangling' references.
155 // This means that if people were doing addValue:[xxx new] and never removing, well, that doesn't work
157 // Second, if we notice standard retain/release implementations we use scanned memory, and fudge the
158 // standard callbacks to generally do nothing if the collection was allocated in GC memory. On special
159 // CF objects, however, like those used for precious resources like video-card buffers, we do indeed
160 // do CFRetain on input and CFRelease on output. The tricky case is GC finalization; we need to remember
161 // that we did the CFReleases so that subsequent collection operations, like removal, don't double CFRelease.
162 // (In fact we don't really use CFRetain/CFRelease but go directly to the collector)
166 __kCFHashFinalized
= (1 << 7),
167 __kCFHashWeakKeys
= (1 << 8),
168 __kCFHashWeakValues
= (1 << 9)
171 typedef uintptr_t any_t
;
172 typedef const void * const_any_pointer_t
;
173 typedef void * any_pointer_t
;
175 struct __CFDictionary
{
177 CFIndex _count
; /* number of values */
178 CFIndex _bucketsNum
; /* number of buckets */
179 CFIndex _bucketsUsed
; /* number of used buckets */
180 CFIndex _bucketsCap
; /* maximum number of used buckets */
183 any_pointer_t _context
; /* private */
184 CFOptionFlags _xflags
;
186 any_t
*_keys
; /* can be NULL if not allocated yet */
187 any_t
*_values
; /* can be NULL if not allocated yet */
190 /* Bits 1-0 of the _xflags are used for mutability variety */
191 /* Bits 3-2 of the _xflags are used for key callback indicator bits */
192 /* Bits 5-4 of the _xflags are used for value callback indicator bits */
193 /* Bit 6 of the _xflags is special KVO actions bit */
194 /* Bits 7,8,9 are GC use */
196 CF_INLINE
bool hasBeenFinalized(CFTypeRef collection
) {
197 return __CFBitfieldGetValue(((const struct __CFDictionary
*)collection
)->_xflags
, 7, 7) != 0;
200 CF_INLINE
void markFinalized(CFTypeRef collection
) {
201 __CFBitfieldSetValue(((struct __CFDictionary
*)collection
)->_xflags
, 7, 7, 1);
205 CF_INLINE CFIndex
__CFHashGetType(CFHashRef hc
) {
206 return __CFBitfieldGetValue(hc
->_xflags
, 1, 0);
209 CF_INLINE CFIndex
__CFDictionaryGetSizeOfType(CFIndex t
) {
210 CFIndex size
= sizeof(struct __CFDictionary
);
211 if (__CFBitfieldGetValue(t
, 3, 2) == __kCFHashHasCustomCallBacks
) {
212 size
+= sizeof(CFDictionaryKeyCallBacks
);
214 if (__CFBitfieldGetValue(t
, 5, 4) == __kCFHashHasCustomCallBacks
) {
215 size
+= sizeof(CFDictionaryValueCallBacks
);
220 CF_INLINE
const CFDictionaryKeyCallBacks
*__CFDictionaryGetKeyCallBacks(CFHashRef hc
) {
221 CFDictionaryKeyCallBacks
*result
= NULL
;
222 switch (__CFBitfieldGetValue(hc
->_xflags
, 3, 2)) {
223 case __kCFHashHasNullCallBacks
:
224 return &__kCFNullDictionaryKeyCallBacks
;
225 case __kCFHashHasCFTypeCallBacks
:
226 return &kCFTypeDictionaryKeyCallBacks
;
227 case __kCFHashHasCustomCallBacks
:
230 result
= (CFDictionaryKeyCallBacks
*)((uint8_t *)hc
+ sizeof(struct __CFDictionary
));
234 CF_INLINE Boolean
__CFDictionaryKeyCallBacksMatchNull(const CFDictionaryKeyCallBacks
*c
) {
236 (c
->retain
== __kCFNullDictionaryKeyCallBacks
.retain
&&
237 c
->release
== __kCFNullDictionaryKeyCallBacks
.release
&&
238 c
->copyDescription
== __kCFNullDictionaryKeyCallBacks
.copyDescription
&&
239 c
->equal
== __kCFNullDictionaryKeyCallBacks
.equal
&&
240 c
->hash
== __kCFNullDictionaryKeyCallBacks
.hash
));
243 CF_INLINE Boolean
__CFDictionaryKeyCallBacksMatchCFType(const CFDictionaryKeyCallBacks
*c
) {
244 return (&kCFTypeDictionaryKeyCallBacks
== c
||
245 (c
->retain
== kCFTypeDictionaryKeyCallBacks
.retain
&&
246 c
->release
== kCFTypeDictionaryKeyCallBacks
.release
&&
247 c
->copyDescription
== kCFTypeDictionaryKeyCallBacks
.copyDescription
&&
248 c
->equal
== kCFTypeDictionaryKeyCallBacks
.equal
&&
249 c
->hash
== kCFTypeDictionaryKeyCallBacks
.hash
));
252 CF_INLINE
const CFDictionaryValueCallBacks
*__CFDictionaryGetValueCallBacks(CFHashRef hc
) {
253 CFDictionaryValueCallBacks
*result
= NULL
;
254 switch (__CFBitfieldGetValue(hc
->_xflags
, 5, 4)) {
255 case __kCFHashHasNullCallBacks
:
256 return &__kCFNullDictionaryValueCallBacks
;
257 case __kCFHashHasCFTypeCallBacks
:
258 return &kCFTypeDictionaryValueCallBacks
;
259 case __kCFHashHasCustomCallBacks
:
262 if (__CFBitfieldGetValue(hc
->_xflags
, 3, 2) == __kCFHashHasCustomCallBacks
) {
263 result
= (CFDictionaryValueCallBacks
*)((uint8_t *)hc
+ sizeof(struct __CFDictionary
) + sizeof(CFDictionaryKeyCallBacks
));
265 result
= (CFDictionaryValueCallBacks
*)((uint8_t *)hc
+ sizeof(struct __CFDictionary
));
270 CF_INLINE Boolean
__CFDictionaryValueCallBacksMatchNull(const CFDictionaryValueCallBacks
*c
) {
272 (c
->retain
== __kCFNullDictionaryValueCallBacks
.retain
&&
273 c
->release
== __kCFNullDictionaryValueCallBacks
.release
&&
274 c
->copyDescription
== __kCFNullDictionaryValueCallBacks
.copyDescription
&&
275 c
->equal
== __kCFNullDictionaryValueCallBacks
.equal
));
278 CF_INLINE Boolean
__CFDictionaryValueCallBacksMatchCFType(const CFDictionaryValueCallBacks
*c
) {
279 return (&kCFTypeDictionaryValueCallBacks
== c
||
280 (c
->retain
== kCFTypeDictionaryValueCallBacks
.retain
&&
281 c
->release
== kCFTypeDictionaryValueCallBacks
.release
&&
282 c
->copyDescription
== kCFTypeDictionaryValueCallBacks
.copyDescription
&&
283 c
->equal
== kCFTypeDictionaryValueCallBacks
.equal
));
286 CFIndex
_CFDictionaryGetKVOBit(CFHashRef hc
) {
287 return __CFBitfieldGetValue(hc
->_xflags
, 6, 6);
290 void _CFDictionarySetKVOBit(CFHashRef hc
, CFIndex bit
) {
291 __CFBitfieldSetValue(((CFMutableHashRef
)hc
)->_xflags
, 6, 6, ((uintptr_t)bit
& 0x1));
294 CF_INLINE Boolean
__CFDictionaryShouldShrink(CFHashRef hc
) {
295 return (__kCFHashMutable
== __CFHashGetType(hc
)) &&
296 !(CF_USING_COLLECTABLE_MEMORY
&& auto_zone_is_finalized(__CFCollectableZone
, hc
)) && /* GC: don't shrink finalizing hcs! */
297 (hc
->_bucketsNum
< 4 * hc
->_deletes
|| (256 <= hc
->_bucketsCap
&& hc
-> _bucketsUsed
< 3 * hc
->_bucketsCap
/ 16));
300 CF_INLINE CFIndex
__CFHashGetOccurrenceCount(CFHashRef hc
, CFIndex idx
) {
302 return hc
->_values
[idx
];
307 CF_INLINE Boolean
__CFHashKeyIsValue(CFHashRef hc
, any_t key
) {
308 return (hc
->_marker
!= key
&& ~hc
->_marker
!= key
) ? true : false;
311 CF_INLINE Boolean
__CFHashKeyIsMagic(CFHashRef hc
, any_t key
) {
312 return (hc
->_marker
== key
|| ~hc
->_marker
== key
) ? true : false;
316 #if !defined(CF_OBJC_KVO_WILLCHANGE)
317 #define CF_OBJC_KVO_WILLCHANGE(obj, key)
318 #define CF_OBJC_KVO_DIDCHANGE(obj, key)
321 CF_INLINE
uintptr_t __CFDictionaryScrambleHash(uintptr_t k
) {
326 uintptr_t a
= 0x4368726973746F70ULL
;
327 uintptr_t b
= 0x686572204B616E65ULL
;
329 uintptr_t a
= 0x4B616E65UL
;
330 uintptr_t b
= 0x4B616E65UL
;
335 a
-= b
; a
-= c
; a
^= (c
>> 43);
336 b
-= c
; b
-= a
; b
^= (a
<< 9);
337 c
-= a
; c
-= b
; c
^= (b
>> 8);
338 a
-= b
; a
-= c
; a
^= (c
>> 38);
339 b
-= c
; b
-= a
; b
^= (a
<< 23);
340 c
-= a
; c
-= b
; c
^= (b
>> 5);
341 a
-= b
; a
-= c
; a
^= (c
>> 35);
342 b
-= c
; b
-= a
; b
^= (a
<< 49);
343 c
-= a
; c
-= b
; c
^= (b
>> 11);
344 a
-= b
; a
-= c
; a
^= (c
>> 12);
345 b
-= c
; b
-= a
; b
^= (a
<< 18);
346 c
-= a
; c
-= b
; c
^= (b
>> 22);
348 a
-= b
; a
-= c
; a
^= (c
>> 13);
349 b
-= c
; b
-= a
; b
^= (a
<< 8);
350 c
-= a
; c
-= b
; c
^= (b
>> 13);
351 a
-= b
; a
-= c
; a
^= (c
>> 12);
352 b
-= c
; b
-= a
; b
^= (a
<< 16);
353 c
-= a
; c
-= b
; c
^= (b
>> 5);
354 a
-= b
; a
-= c
; a
^= (c
>> 3);
355 b
-= c
; b
-= a
; b
^= (a
<< 10);
356 c
-= a
; c
-= b
; c
^= (b
>> 15);
362 static CFIndex
__CFDictionaryFindBuckets1a(CFHashRef hc
, any_t key
) {
363 CFHashCode keyHash
= (CFHashCode
)key
;
364 keyHash
= __CFDictionaryScrambleHash(keyHash
);
365 any_t
*keys
= hc
->_keys
;
366 any_t marker
= hc
->_marker
;
367 CFIndex probe
= keyHash
& (hc
->_bucketsNum
- 1);
368 CFIndex probeskip
= 1; // See RemoveValue() for notes before changing this value
369 CFIndex start
= probe
;
371 any_t currKey
= keys
[probe
];
372 if (marker
== currKey
) { /* empty */
374 } else if (~marker
== currKey
) { /* deleted */
376 } else if (currKey
== key
) {
379 probe
= probe
+ probeskip
;
380 // This alternative to probe % buckets assumes that
381 // probeskip is always positive and less than the
382 // number of buckets.
383 if (hc
->_bucketsNum
<= probe
) {
384 probe
-= hc
->_bucketsNum
;
386 if (start
== probe
) {
392 static CFIndex
__CFDictionaryFindBuckets1b(CFHashRef hc
, any_t key
) {
393 const CFDictionaryKeyCallBacks
*cb
= __CFDictionaryGetKeyCallBacks(hc
);
394 CFHashCode keyHash
= cb
->hash
? (CFHashCode
)INVOKE_CALLBACK2(((CFHashCode (*)(any_t
, any_pointer_t
))cb
->hash
), key
, hc
->_context
) : (CFHashCode
)key
;
395 keyHash
= __CFDictionaryScrambleHash(keyHash
);
396 any_t
*keys
= hc
->_keys
;
397 any_t marker
= hc
->_marker
;
398 CFIndex probe
= keyHash
& (hc
->_bucketsNum
- 1);
399 CFIndex probeskip
= 1; // See RemoveValue() for notes before changing this value
400 CFIndex start
= probe
;
402 any_t currKey
= keys
[probe
];
403 if (marker
== currKey
) { /* empty */
405 } else if (~marker
== currKey
) { /* deleted */
407 } else if (currKey
== key
|| (cb
->equal
&& INVOKE_CALLBACK3((Boolean (*)(any_t
, any_t
, any_pointer_t
))cb
->equal
, currKey
, key
, hc
->_context
))) {
410 probe
= probe
+ probeskip
;
411 // This alternative to probe % buckets assumes that
412 // probeskip is always positive and less than the
413 // number of buckets.
414 if (hc
->_bucketsNum
<= probe
) {
415 probe
-= hc
->_bucketsNum
;
417 if (start
== probe
) {
423 CF_INLINE CFIndex
__CFDictionaryFindBuckets1(CFHashRef hc
, any_t key
) {
424 if (__kCFHashHasNullCallBacks
== __CFBitfieldGetValue(hc
->_xflags
, 3, 2)) {
425 return __CFDictionaryFindBuckets1a(hc
, key
);
427 return __CFDictionaryFindBuckets1b(hc
, key
);
430 static void __CFDictionaryFindBuckets2(CFHashRef hc
, any_t key
, CFIndex
*match
, CFIndex
*nomatch
) {
431 const CFDictionaryKeyCallBacks
*cb
= __CFDictionaryGetKeyCallBacks(hc
);
432 CFHashCode keyHash
= cb
->hash
? (CFHashCode
)INVOKE_CALLBACK2(((CFHashCode (*)(any_t
, any_pointer_t
))cb
->hash
), key
, hc
->_context
) : (CFHashCode
)key
;
433 keyHash
= __CFDictionaryScrambleHash(keyHash
);
434 any_t
*keys
= hc
->_keys
;
435 any_t marker
= hc
->_marker
;
436 CFIndex probe
= keyHash
& (hc
->_bucketsNum
- 1);
437 CFIndex probeskip
= 1; // See RemoveValue() for notes before changing this value
438 CFIndex start
= probe
;
439 *match
= kCFNotFound
;
440 *nomatch
= kCFNotFound
;
442 any_t currKey
= keys
[probe
];
443 if (marker
== currKey
) { /* empty */
444 if (nomatch
) *nomatch
= probe
;
446 } else if (~marker
== currKey
) { /* deleted */
451 } else if (currKey
== key
|| (cb
->equal
&& INVOKE_CALLBACK3((Boolean (*)(any_t
, any_t
, any_pointer_t
))cb
->equal
, currKey
, key
, hc
->_context
))) {
455 probe
= probe
+ probeskip
;
456 // This alternative to probe % buckets assumes that
457 // probeskip is always positive and less than the
458 // number of buckets.
459 if (hc
->_bucketsNum
<= probe
) {
460 probe
-= hc
->_bucketsNum
;
462 if (start
== probe
) {
468 static void __CFDictionaryFindNewMarker(CFHashRef hc
) {
469 any_t
*keys
= hc
->_keys
;
471 CFIndex idx
, nbuckets
;
474 nbuckets
= hc
->_bucketsNum
;
475 newMarker
= hc
->_marker
;
479 for (idx
= 0; idx
< nbuckets
; idx
++) {
480 if (newMarker
== keys
[idx
] || ~newMarker
== keys
[idx
]) {
486 for (idx
= 0; idx
< nbuckets
; idx
++) {
487 if (hc
->_marker
== keys
[idx
]) {
488 keys
[idx
] = newMarker
;
489 } else if (~hc
->_marker
== keys
[idx
]) {
490 keys
[idx
] = ~newMarker
;
493 ((struct __CFDictionary
*)hc
)->_marker
= newMarker
;
496 static Boolean
__CFDictionaryEqual(CFTypeRef cf1
, CFTypeRef cf2
) {
497 CFHashRef hc1
= (CFHashRef
)cf1
;
498 CFHashRef hc2
= (CFHashRef
)cf2
;
499 const CFDictionaryKeyCallBacks
*cb1
, *cb2
;
500 const CFDictionaryValueCallBacks
*vcb1
, *vcb2
;
502 CFIndex idx
, nbuckets
;
503 if (hc1
== hc2
) return true;
504 if (hc1
->_count
!= hc2
->_count
) return false;
505 cb1
= __CFDictionaryGetKeyCallBacks(hc1
);
506 cb2
= __CFDictionaryGetKeyCallBacks(hc2
);
507 if (cb1
->equal
!= cb2
->equal
) return false;
508 vcb1
= __CFDictionaryGetValueCallBacks(hc1
);
509 vcb2
= __CFDictionaryGetValueCallBacks(hc2
);
510 if (vcb1
->equal
!= vcb2
->equal
) return false;
511 if (0 == hc1
->_bucketsUsed
) return true; /* after function comparison! */
513 nbuckets
= hc1
->_bucketsNum
;
514 for (idx
= 0; idx
< nbuckets
; idx
++) {
515 if (hc1
->_marker
!= keys
[idx
] && ~hc1
->_marker
!= keys
[idx
]) {
517 const_any_pointer_t value
;
518 if (!CFDictionaryGetValueIfPresent(hc2
, (any_pointer_t
)keys
[idx
], &value
)) return false;
519 if (hc1
->_values
[idx
] != (any_t
)value
) {
520 if (NULL
== vcb1
->equal
) return false;
521 if (!INVOKE_CALLBACK3((Boolean (*)(any_t
, any_t
, any_pointer_t
))vcb1
->equal
, hc1
->_values
[idx
], (any_t
)value
, hc1
->_context
)) return false;
525 const_any_pointer_t value
;
526 if (!CFDictionaryGetValueIfPresent(hc2
, (any_pointer_t
)keys
[idx
], &value
)) return false;
529 if (hc1
->_values
[idx
] != CFDictionaryGetCountOfValue(hc2
, (any_pointer_t
)keys
[idx
])) return false;
536 static CFHashCode
__CFDictionaryHash(CFTypeRef cf
) {
537 CFHashRef hc
= (CFHashRef
)cf
;
541 static CFStringRef
__CFDictionaryCopyDescription(CFTypeRef cf
) {
542 CFHashRef hc
= (CFHashRef
)cf
;
543 CFAllocatorRef allocator
;
544 const CFDictionaryKeyCallBacks
*cb
;
545 const CFDictionaryValueCallBacks
*vcb
;
547 CFIndex idx
, nbuckets
;
548 CFMutableStringRef result
;
549 cb
= __CFDictionaryGetKeyCallBacks(hc
);
550 vcb
= __CFDictionaryGetValueCallBacks(hc
);
552 nbuckets
= hc
->_bucketsNum
;
553 allocator
= CFGetAllocator(hc
);
554 result
= CFStringCreateMutable(allocator
, 0);
555 const char *type
= "?";
556 switch (__CFHashGetType(hc
)) {
557 case __kCFHashImmutable
: type
= "immutable"; break;
558 case __kCFHashMutable
: type
= "mutable"; break;
560 CFStringAppendFormat(result
, NULL
, CFSTR("<CFDictionary %p [%p]>{type = %s, count = %u, capacity = %u, pairs = (\n"), cf
, allocator
, type
, hc
->_count
, hc
->_bucketsCap
);
561 for (idx
= 0; idx
< nbuckets
; idx
++) {
562 if (__CFHashKeyIsValue(hc
, keys
[idx
])) {
563 CFStringRef kDesc
= NULL
, vDesc
= NULL
;
564 if (NULL
!= cb
->copyDescription
) {
565 kDesc
= (CFStringRef
)INVOKE_CALLBACK2(((CFStringRef (*)(any_t
, any_pointer_t
))cb
->copyDescription
), keys
[idx
], hc
->_context
);
567 if (NULL
!= vcb
->copyDescription
) {
568 vDesc
= (CFStringRef
)INVOKE_CALLBACK2(((CFStringRef (*)(any_t
, any_pointer_t
))vcb
->copyDescription
), hc
->_values
[idx
], hc
->_context
);
571 if (NULL
!= kDesc
&& NULL
!= vDesc
) {
572 CFStringAppendFormat(result
, NULL
, CFSTR("\t%u : %@ = %@\n"), idx
, kDesc
, vDesc
);
575 } else if (NULL
!= kDesc
) {
576 CFStringAppendFormat(result
, NULL
, CFSTR("\t%u : %@ = <%p>\n"), idx
, kDesc
, hc
->_values
[idx
]);
578 } else if (NULL
!= vDesc
) {
579 CFStringAppendFormat(result
, NULL
, CFSTR("\t%u : <%p> = %@\n"), idx
, keys
[idx
], vDesc
);
582 CFStringAppendFormat(result
, NULL
, CFSTR("\t%u : <%p> = <%p>\n"), idx
, keys
[idx
], hc
->_values
[idx
]);
587 CFStringAppendFormat(result
, NULL
, CFSTR("\t%u : %@\n"), idx
, kDesc
);
590 CFStringAppendFormat(result
, NULL
, CFSTR("\t%u : <%p>\n"), idx
, keys
[idx
]);
595 CFStringAppendFormat(result
, NULL
, CFSTR("\t%u : %@ (%ld)\n"), idx
, kDesc
, hc
->_values
[idx
]);
598 CFStringAppendFormat(result
, NULL
, CFSTR("\t%u : <%p> (%ld)\n"), idx
, keys
[idx
], hc
->_values
[idx
]);
603 CFStringAppend(result
, CFSTR(")}"));
607 static void __CFDictionaryDeallocate(CFTypeRef cf
) {
608 CFMutableHashRef hc
= (CFMutableHashRef
)cf
;
609 CFAllocatorRef allocator
= __CFGetAllocator(hc
);
610 const CFDictionaryKeyCallBacks
*cb
= __CFDictionaryGetKeyCallBacks(hc
);
611 const CFDictionaryValueCallBacks
*vcb
= __CFDictionaryGetValueCallBacks(hc
);
613 // mark now in case any callout somehow tries to add an entry back in
615 if (vcb
->release
|| cb
->release
) {
616 any_t
*keys
= hc
->_keys
;
617 CFIndex idx
, nbuckets
= hc
->_bucketsNum
;
618 for (idx
= 0; idx
< nbuckets
; idx
++) {
619 any_t oldkey
= keys
[idx
];
620 if (hc
->_marker
!= oldkey
&& ~hc
->_marker
!= oldkey
) {
622 INVOKE_CALLBACK3(((void (*)(CFAllocatorRef
, any_t
, any_pointer_t
))vcb
->release
), allocator
, hc
->_values
[idx
], hc
->_context
);
625 INVOKE_CALLBACK3(((void (*)(CFAllocatorRef
, any_t
, any_pointer_t
))cb
->release
), allocator
, oldkey
, hc
->_context
);
631 if (CF_IS_COLLECTABLE_ALLOCATOR(allocator
)) {
632 // return early so that contents are preserved after finalization
636 _CFAllocatorDeallocateGC(allocator
, hc
->_keys
);
637 #if CFDictionary || CFBag
638 _CFAllocatorDeallocateGC(allocator
, hc
->_values
);
642 hc
->_count
= 0; // GC: also zero count, so the hc will appear empty.
643 hc
->_bucketsUsed
= 0;
647 static CFTypeID __kCFDictionaryTypeID
= _kCFRuntimeNotATypeID
;
649 static const CFRuntimeClass __CFDictionaryClass
= {
650 _kCFRuntimeScannedObject
,
654 __CFDictionaryDeallocate
,
658 __CFDictionaryCopyDescription
661 __private_extern__
void __CFDictionaryInitialize(void) {
662 __kCFHashTypeID
= _CFRuntimeRegisterClass(&__CFDictionaryClass
);
665 CFTypeID
CFDictionaryGetTypeID(void) {
666 return __kCFHashTypeID
;
669 static CFMutableHashRef
__CFDictionaryInit(CFAllocatorRef allocator
, CFOptionFlags flags
, CFIndex capacity
, const CFDictionaryKeyCallBacks
*keyCallBacks
671 , const CFDictionaryValueCallBacks
*valueCallBacks
674 struct __CFDictionary
*hc
;
676 __CFBitfieldSetValue(flags
, 31, 2, 0);
677 CFOptionFlags xflags
= 0;
678 if (CF_IS_COLLECTABLE_ALLOCATOR(allocator
)) {
679 // preserve NULL for key or value CB, otherwise fix up.
680 if (!keyCallBacks
|| (keyCallBacks
->retain
== NULL
&& keyCallBacks
->release
== NULL
)) {
681 xflags
= __kCFHashWeakKeys
;
684 if (!valueCallBacks
|| (valueCallBacks
->retain
== NULL
&& valueCallBacks
->release
== NULL
)) {
685 xflags
|= __kCFHashWeakValues
;
689 xflags
|= __kCFHashWeakValues
;
692 if (__CFDictionaryKeyCallBacksMatchNull(keyCallBacks
)) {
693 __CFBitfieldSetValue(flags
, 3, 2, __kCFHashHasNullCallBacks
);
694 } else if (__CFDictionaryKeyCallBacksMatchCFType(keyCallBacks
)) {
695 __CFBitfieldSetValue(flags
, 3, 2, __kCFHashHasCFTypeCallBacks
);
697 __CFBitfieldSetValue(flags
, 3, 2, __kCFHashHasCustomCallBacks
);
700 if (__CFDictionaryValueCallBacksMatchNull(valueCallBacks
)) {
701 __CFBitfieldSetValue(flags
, 5, 4, __kCFHashHasNullCallBacks
);
702 } else if (__CFDictionaryValueCallBacksMatchCFType(valueCallBacks
)) {
703 __CFBitfieldSetValue(flags
, 5, 4, __kCFHashHasCFTypeCallBacks
);
705 __CFBitfieldSetValue(flags
, 5, 4, __kCFHashHasCustomCallBacks
);
708 size
= __CFDictionaryGetSizeOfType(flags
) - sizeof(CFRuntimeBase
);
709 hc
= (struct __CFDictionary
*)_CFRuntimeCreateInstance(allocator
, __kCFHashTypeID
, size
, NULL
);
714 hc
->_bucketsUsed
= 0;
715 hc
->_marker
= (any_t
)0xa1b1c1d3;
719 hc
->_xflags
= xflags
| flags
;
720 switch (__CFBitfieldGetValue(flags
, 1, 0)) {
721 case __kCFHashImmutable
:
722 if (__CFOASafe
) __CFSetLastAllocationEventName(hc
, "CFDictionary (immutable)");
724 case __kCFHashMutable
:
725 if (__CFOASafe
) __CFSetLastAllocationEventName(hc
, "CFDictionary (mutable-variable)");
728 hc
->_bucketsCap
= __CFHashRoundUpCapacity(1);
732 if (__kCFHashHasCustomCallBacks
== __CFBitfieldGetValue(flags
, 3, 2)) {
733 CFDictionaryKeyCallBacks
*cb
= (CFDictionaryKeyCallBacks
*)__CFDictionaryGetKeyCallBacks((CFHashRef
)hc
);
735 FAULT_CALLBACK((void **)&(cb
->retain
));
736 FAULT_CALLBACK((void **)&(cb
->release
));
737 FAULT_CALLBACK((void **)&(cb
->copyDescription
));
738 FAULT_CALLBACK((void **)&(cb
->equal
));
739 FAULT_CALLBACK((void **)&(cb
->hash
));
742 if (__kCFHashHasCustomCallBacks
== __CFBitfieldGetValue(flags
, 5, 4)) {
743 CFDictionaryValueCallBacks
*vcb
= (CFDictionaryValueCallBacks
*)__CFDictionaryGetValueCallBacks((CFHashRef
)hc
);
744 *vcb
= *valueCallBacks
;
745 FAULT_CALLBACK((void **)&(vcb
->retain
));
746 FAULT_CALLBACK((void **)&(vcb
->release
));
747 FAULT_CALLBACK((void **)&(vcb
->copyDescription
));
748 FAULT_CALLBACK((void **)&(vcb
->equal
));
755 CFHashRef
CFDictionaryCreate(CFAllocatorRef allocator
, const_any_pointer_t
*keys
, const_any_pointer_t
*values
, CFIndex numValues
, const CFDictionaryKeyCallBacks
*keyCallBacks
, const CFDictionaryValueCallBacks
*valueCallBacks
) {
758 CFHashRef
CFDictionaryCreate(CFAllocatorRef allocator
, const_any_pointer_t
*keys
, CFIndex numValues
, const CFDictionaryKeyCallBacks
*keyCallBacks
) {
760 CFAssert2(0 <= numValues
, __kCFLogAssertion
, "%s(): numValues (%ld) cannot be less than zero", __PRETTY_FUNCTION__
, numValues
);
762 CFMutableHashRef hc
= __CFDictionaryInit(allocator
, __kCFHashImmutable
, numValues
, keyCallBacks
, valueCallBacks
);
765 CFMutableHashRef hc
= __CFDictionaryInit(allocator
, __kCFHashImmutable
, numValues
, keyCallBacks
);
767 __CFBitfieldSetValue(hc
->_xflags
, 1, 0, __kCFHashMutable
);
768 for (CFIndex idx
= 0; idx
< numValues
; idx
++) {
770 CFDictionaryAddValue(hc
, keys
[idx
], values
[idx
]);
773 CFDictionaryAddValue(hc
, keys
[idx
]);
776 __CFBitfieldSetValue(hc
->_xflags
, 1, 0, __kCFHashImmutable
);
777 return (CFHashRef
)hc
;
781 CFMutableHashRef
CFDictionaryCreateMutable(CFAllocatorRef allocator
, CFIndex capacity
, const CFDictionaryKeyCallBacks
*keyCallBacks
, const CFDictionaryValueCallBacks
*valueCallBacks
) {
784 CFMutableHashRef
CFDictionaryCreateMutable(CFAllocatorRef allocator
, CFIndex capacity
, const CFDictionaryKeyCallBacks
*keyCallBacks
) {
786 CFAssert2(0 <= capacity
, __kCFLogAssertion
, "%s(): capacity (%ld) cannot be less than zero", __PRETTY_FUNCTION__
, capacity
);
788 CFMutableHashRef hc
= __CFDictionaryInit(allocator
, __kCFHashMutable
, capacity
, keyCallBacks
, valueCallBacks
);
791 CFMutableHashRef hc
= __CFDictionaryInit(allocator
, __kCFHashMutable
, capacity
, keyCallBacks
);
796 #if CFDictionary || CFSet
797 // does not have Add semantics for Bag; it has Set semantics ... is that best?
798 static void __CFDictionaryGrow(CFMutableHashRef hc
, CFIndex numNewValues
);
800 // This creates a hc which is for CFTypes or NSObjects, with a CFRetain style ownership transfer;
801 // the hc does not take a retain (since it claims 1), and the caller does not need to release the inserted objects (since we do it).
802 // The incoming objects must also be collectable if allocated out of a collectable allocator - and are neither released nor retained.
804 CFHashRef
_CFDictionaryCreate_ex(CFAllocatorRef allocator
, Boolean isMutable
, const_any_pointer_t
*keys
, const_any_pointer_t
*values
, CFIndex numValues
) {
807 CFHashRef
_CFDictionaryCreate_ex(CFAllocatorRef allocator
, Boolean isMutable
, const_any_pointer_t
*keys
, CFIndex numValues
) {
809 CFAssert2(0 <= numValues
, __kCFLogAssertion
, "%s(): numValues (%ld) cannot be less than zero", __PRETTY_FUNCTION__
, numValues
);
811 CFMutableHashRef hc
= __CFDictionaryInit(allocator
, __kCFHashMutable
, numValues
, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
814 CFMutableHashRef hc
= __CFDictionaryInit(allocator
, __kCFHashMutable
, numValues
, &kCFTypeDictionaryKeyCallBacks
);
816 __CFDictionaryGrow(hc
, numValues
);
817 for (CFIndex idx
= 0; idx
< numValues
; idx
++) {
818 CFIndex match
, nomatch
;
819 __CFDictionaryFindBuckets2(hc
, (any_t
)keys
[idx
], &match
, &nomatch
);
820 if (kCFNotFound
== match
) {
821 CFAllocatorRef allocator
= __CFGetAllocator(hc
);
822 any_t newKey
= (any_t
)keys
[idx
];
823 if (__CFHashKeyIsMagic(hc
, newKey
)) {
824 __CFDictionaryFindNewMarker(hc
);
826 if (hc
->_keys
[nomatch
] == ~hc
->_marker
) {
829 CFAllocatorRef keysAllocator
= (hc
->_xflags
& __kCFHashWeakKeys
) ? kCFAllocatorNull
: allocator
;
830 CF_WRITE_BARRIER_ASSIGN(keysAllocator
, hc
->_keys
[nomatch
], newKey
);
832 any_t newValue
= (any_t
)values
[idx
];
833 CFAllocatorRef valuesAllocator
= (hc
->_xflags
& __kCFHashWeakValues
) ? kCFAllocatorNull
: allocator
;
834 CF_WRITE_BARRIER_ASSIGN(valuesAllocator
, hc
->_values
[nomatch
], newValue
);
837 hc
->_values
[nomatch
] = 1;
842 CFAllocatorRef allocator
= __CFGetAllocator(hc
);
844 any_t oldKey
= hc
->_keys
[match
];
845 any_t newKey
= (any_t
)keys
[idx
];
846 CFAllocatorRef keysAllocator
= (hc
->_xflags
& __kCFHashWeakKeys
) ? kCFAllocatorNull
: allocator
;
847 CF_WRITE_BARRIER_ASSIGN(keysAllocator
, hc
->_keys
[match
], ~hc
->_marker
);
848 if (__CFHashKeyIsMagic(hc
, newKey
)) {
849 __CFDictionaryFindNewMarker(hc
);
851 CF_WRITE_BARRIER_ASSIGN(keysAllocator
, hc
->_keys
[match
], newKey
);
855 any_t oldValue
= hc
->_values
[match
];
856 any_t newValue
= (any_t
)values
[idx
];
857 CFAllocatorRef valuesAllocator
= (hc
->_xflags
& __kCFHashWeakValues
) ? kCFAllocatorNull
: allocator
;
858 CF_WRITE_BARRIER_ASSIGN(valuesAllocator
, hc
->_values
[match
], newValue
);
859 RELEASEVALUE(oldValue
);
863 if (!isMutable
) __CFBitfieldSetValue(hc
->_xflags
, 1, 0, __kCFHashImmutable
);
864 return (CFHashRef
)hc
;
868 CFHashRef
CFDictionaryCreateCopy(CFAllocatorRef allocator
, CFHashRef other
) {
869 CFMutableHashRef hc
= CFDictionaryCreateMutableCopy(allocator
, CFDictionaryGetCount(other
), other
);
870 __CFBitfieldSetValue(hc
->_xflags
, 1, 0, __kCFHashImmutable
);
871 if (__CFOASafe
) __CFSetLastAllocationEventName(hc
, "CFDictionary (immutable)");
875 CFMutableHashRef
CFDictionaryCreateMutableCopy(CFAllocatorRef allocator
, CFIndex capacity
, CFHashRef other
) {
876 CFIndex numValues
= CFDictionaryGetCount(other
);
877 const_any_pointer_t
*list
, buffer
[256];
878 list
= (numValues
<= 256) ? buffer
: (const_any_pointer_t
*)CFAllocatorAllocate(allocator
, numValues
* sizeof(const_any_pointer_t
), 0);
879 if (list
!= buffer
&& __CFOASafe
) __CFSetLastAllocationEventName(list
, "CFDictionary (temp)");
881 const_any_pointer_t
*vlist
, vbuffer
[256];
882 vlist
= (numValues
<= 256) ? vbuffer
: (const_any_pointer_t
*)CFAllocatorAllocate(allocator
, numValues
* sizeof(const_any_pointer_t
), 0);
883 if (vlist
!= vbuffer
&& __CFOASafe
) __CFSetLastAllocationEventName(vlist
, "CFDictionary (temp)");
886 CFDictionaryGetValues(other
, list
);
889 CFDictionaryGetKeysAndValues(other
, list
, vlist
);
891 const CFDictionaryKeyCallBacks
*kcb
;
892 const CFDictionaryValueCallBacks
*vcb
;
893 if (CF_IS_OBJC(__kCFHashTypeID
, other
)) {
894 kcb
= &kCFTypeDictionaryKeyCallBacks
;
895 vcb
= &kCFTypeDictionaryValueCallBacks
;
897 kcb
= __CFDictionaryGetKeyCallBacks(other
);
898 vcb
= __CFDictionaryGetValueCallBacks(other
);
901 CFMutableHashRef hc
= __CFDictionaryInit(allocator
, __kCFHashMutable
, capacity
, kcb
, vcb
);
904 CFMutableHashRef hc
= __CFDictionaryInit(allocator
, __kCFHashMutable
, capacity
, kcb
);
906 if (0 == capacity
) _CFDictionarySetCapacity(hc
, numValues
);
907 for (CFIndex idx
= 0; idx
< numValues
; idx
++) {
909 CFDictionaryAddValue(hc
, list
[idx
], vlist
[idx
]);
912 CFDictionaryAddValue(hc
, list
[idx
]);
915 if (list
!= buffer
) CFAllocatorDeallocate(allocator
, list
);
917 if (vlist
!= vbuffer
) CFAllocatorDeallocate(allocator
, vlist
);
922 // Used by NSHashTables/NSMapTables and KVO
923 void _CFDictionarySetContext(CFHashRef hc
, any_pointer_t context
) {
924 __CFGenericValidateType(hc
, __kCFHashTypeID
);
925 CF_WRITE_BARRIER_BASE_ASSIGN(__CFGetAllocator(hc
), hc
, hc
->_context
, context
);
928 any_pointer_t
_CFDictionaryGetContext(CFHashRef hc
) {
929 __CFGenericValidateType(hc
, __kCFHashTypeID
);
933 CFIndex
CFDictionaryGetCount(CFHashRef hc
) {
934 if (CFDictionary
|| CFSet
) CF_OBJC_FUNCDISPATCH0(__kCFHashTypeID
, CFIndex
, hc
, "count");
935 __CFGenericValidateType(hc
, __kCFHashTypeID
);
940 CFIndex
CFDictionaryGetCountOfKey(CFHashRef hc
, const_any_pointer_t key
) {
943 CFIndex
CFDictionaryGetCountOfValue(CFHashRef hc
, const_any_pointer_t key
) {
945 if (CFDictionary
) CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID
, CFIndex
, hc
, "countForKey:", key
);
946 if (CFSet
) CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID
, CFIndex
, hc
, "countForObject:", key
);
947 __CFGenericValidateType(hc
, __kCFHashTypeID
);
948 if (0 == hc
->_bucketsUsed
) return 0;
949 CFIndex match
= __CFDictionaryFindBuckets1(hc
, (any_t
)key
);
950 return (kCFNotFound
!= match
? __CFHashGetOccurrenceCount(hc
, match
) : 0);
954 Boolean
CFDictionaryContainsKey(CFHashRef hc
, const_any_pointer_t key
) {
957 Boolean
CFDictionaryContainsValue(CFHashRef hc
, const_any_pointer_t key
) {
959 if (CFDictionary
) CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID
, char, hc
, "containsKey:", key
);
960 if (CFSet
) CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID
, char, hc
, "containsObject:", key
);
961 __CFGenericValidateType(hc
, __kCFHashTypeID
);
962 if (0 == hc
->_bucketsUsed
) return false;
963 CFIndex match
= __CFDictionaryFindBuckets1(hc
, (any_t
)key
);
964 return (kCFNotFound
!= match
? true : false);
968 CFIndex
CFDictionaryGetCountOfValue(CFHashRef hc
, const_any_pointer_t value
) {
969 CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID
, CFIndex
, hc
, "countForObject:", value
);
970 __CFGenericValidateType(hc
, __kCFHashTypeID
);
971 if (0 == hc
->_bucketsUsed
) return 0;
972 any_t
*keys
= hc
->_keys
;
973 Boolean (*equal
)(any_t
, any_t
, any_pointer_t
) = (Boolean (*)(any_t
, any_t
, any_pointer_t
))__CFDictionaryGetValueCallBacks(hc
)->equal
;
975 for (CFIndex idx
= 0, nbuckets
= hc
->_bucketsNum
; idx
< nbuckets
; idx
++) {
976 if (__CFHashKeyIsValue(hc
, keys
[idx
])) {
977 if ((hc
->_values
[idx
] == (any_t
)value
) || (equal
&& INVOKE_CALLBACK3(equal
, hc
->_values
[idx
], (any_t
)value
, hc
->_context
))) {
985 Boolean
CFDictionaryContainsValue(CFHashRef hc
, const_any_pointer_t value
) {
986 CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID
, char, hc
, "containsObject:", value
);
987 __CFGenericValidateType(hc
, __kCFHashTypeID
);
988 if (0 == hc
->_bucketsUsed
) return false;
989 any_t
*keys
= hc
->_keys
;
990 Boolean (*equal
)(any_t
, any_t
, any_pointer_t
) = (Boolean (*)(any_t
, any_t
, any_pointer_t
))__CFDictionaryGetValueCallBacks(hc
)->equal
;
991 for (CFIndex idx
= 0, nbuckets
= hc
->_bucketsNum
; idx
< nbuckets
; idx
++) {
992 if (__CFHashKeyIsValue(hc
, keys
[idx
])) {
993 if ((hc
->_values
[idx
] == (any_t
)value
) || (equal
&& INVOKE_CALLBACK3(equal
, hc
->_values
[idx
], (any_t
)value
, hc
->_context
))) {
1002 const_any_pointer_t
CFDictionaryGetValue(CFHashRef hc
, const_any_pointer_t key
) {
1003 if (CFDictionary
) CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID
, const_any_pointer_t
, hc
, "objectForKey:", key
);
1004 if (CFSet
) CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID
, const_any_pointer_t
, hc
, "member:", key
);
1005 __CFGenericValidateType(hc
, __kCFHashTypeID
);
1006 if (0 == hc
->_bucketsUsed
) return 0;
1007 CFIndex match
= __CFDictionaryFindBuckets1(hc
, (any_t
)key
);
1008 return (kCFNotFound
!= match
? (const_any_pointer_t
)(CFDictionary
? hc
->_values
[match
] : hc
->_keys
[match
]) : 0);
1011 Boolean
CFDictionaryGetValueIfPresent(CFHashRef hc
, const_any_pointer_t key
, const_any_pointer_t
*value
) {
1012 if (CFDictionary
) CF_OBJC_FUNCDISPATCH2(__kCFHashTypeID
, Boolean
, hc
, "_getValue:forKey:", (any_t
*)value
, key
);
1013 if (CFSet
) CF_OBJC_FUNCDISPATCH2(__kCFHashTypeID
, Boolean
, hc
, "_getValue:forObj:", (any_t
*)value
, key
);
1014 __CFGenericValidateType(hc
, __kCFHashTypeID
);
1015 if (0 == hc
->_bucketsUsed
) return false;
1016 CFIndex match
= __CFDictionaryFindBuckets1(hc
, (any_t
)key
);
1017 return (kCFNotFound
!= match
? ((value
? __CFObjCStrongAssign((const_any_pointer_t
)(CFDictionary
? hc
->_values
[match
] : hc
->_keys
[match
]), value
) : 0), true) : false);
1021 Boolean
CFDictionaryGetKeyIfPresent(CFHashRef hc
, const_any_pointer_t key
, const_any_pointer_t
*actualkey
) {
1022 CF_OBJC_FUNCDISPATCH2(__kCFHashTypeID
, Boolean
, hc
, "getActualKey:forKey:", actualkey
, key
);
1023 __CFGenericValidateType(hc
, __kCFHashTypeID
);
1024 if (0 == hc
->_bucketsUsed
) return false;
1025 CFIndex match
= __CFDictionaryFindBuckets1(hc
, (any_t
)key
);
1026 return (kCFNotFound
!= match
? ((actualkey
? __CFObjCStrongAssign((const_any_pointer_t
)hc
->_keys
[match
], actualkey
) : NULL
), true) : false);
1031 void CFDictionaryGetKeysAndValues(CFHashRef hc
, const_any_pointer_t
*keybuf
, const_any_pointer_t
*valuebuf
) {
1034 void CFDictionaryGetValues(CFHashRef hc
, const_any_pointer_t
*keybuf
) {
1035 const_any_pointer_t
*valuebuf
= 0;
1037 if (CFDictionary
) CF_OBJC_FUNCDISPATCH2(__kCFHashTypeID
, void, hc
, "getObjects:andKeys:", (any_t
*)valuebuf
, (any_t
*)keybuf
);
1038 if (CFSet
) CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID
, void, hc
, "getObjects:", (any_t
*)keybuf
);
1039 __CFGenericValidateType(hc
, __kCFHashTypeID
);
1040 if (CF_USING_COLLECTABLE_MEMORY
) {
1041 // GC: speculatively issue a write-barrier on the copied to buffers
1042 __CFObjCWriteBarrierRange(keybuf
, hc
->_count
* sizeof(any_t
));
1043 __CFObjCWriteBarrierRange(valuebuf
, hc
->_count
* sizeof(any_t
));
1045 any_t
*keys
= hc
->_keys
;
1046 for (CFIndex idx
= 0, nbuckets
= hc
->_bucketsNum
; idx
< nbuckets
; idx
++) {
1047 if (__CFHashKeyIsValue(hc
, keys
[idx
])) {
1048 for (CFIndex cnt
= __CFHashGetOccurrenceCount(hc
, idx
); cnt
--;) {
1049 if (keybuf
) *keybuf
++ = (const_any_pointer_t
)keys
[idx
];
1050 if (valuebuf
) *valuebuf
++ = (const_any_pointer_t
)hc
->_values
[idx
];
1056 #if CFDictionary || CFSet
1057 unsigned long _CFDictionaryFastEnumeration(CFHashRef hc
, struct __objcFastEnumerationStateEquivalent
*state
, void *stackbuffer
, unsigned long count
) {
1058 /* copy as many as count items over */
1059 if (0 == state
->state
) { /* first time */
1060 state
->mutationsPtr
= (unsigned long *)&hc
->_mutations
;
1062 state
->itemsPtr
= (unsigned long *)stackbuffer
;
1064 any_t
*keys
= hc
->_keys
;
1065 for (CFIndex idx
= (CFIndex
)state
->state
, nbuckets
= hc
->_bucketsNum
; idx
< nbuckets
&& cnt
< (CFIndex
)count
; idx
++) {
1066 if (__CFHashKeyIsValue(hc
, keys
[idx
])) {
1067 state
->itemsPtr
[cnt
++] = (unsigned long)keys
[idx
];
1075 void CFDictionaryApplyFunction(CFHashRef hc
, CFDictionaryApplierFunction applier
, any_pointer_t context
) {
1076 FAULT_CALLBACK((void **)&(applier
));
1077 if (CFDictionary
) CF_OBJC_FUNCDISPATCH2(__kCFHashTypeID
, void, hc
, "_apply:context:", applier
, context
);
1078 if (CFSet
) CF_OBJC_FUNCDISPATCH2(__kCFHashTypeID
, void, hc
, "_applyValues:context:", applier
, context
);
1079 __CFGenericValidateType(hc
, __kCFHashTypeID
);
1080 any_t
*keys
= hc
->_keys
;
1081 for (CFIndex idx
= 0, nbuckets
= hc
->_bucketsNum
; idx
< nbuckets
; idx
++) {
1082 if (__CFHashKeyIsValue(hc
, keys
[idx
])) {
1083 for (CFIndex cnt
= __CFHashGetOccurrenceCount(hc
, idx
); cnt
--;) {
1085 INVOKE_CALLBACK3(applier
, (const_any_pointer_t
)keys
[idx
], (const_any_pointer_t
)hc
->_values
[idx
], context
);
1088 INVOKE_CALLBACK2(applier
, (const_any_pointer_t
)keys
[idx
], context
);
1095 static void __CFDictionaryGrow(CFMutableHashRef hc
, CFIndex numNewValues
) {
1096 any_t
*oldkeys
= hc
->_keys
;
1097 any_t
*oldvalues
= hc
->_values
;
1098 CFIndex nbuckets
= hc
->_bucketsNum
;
1099 hc
->_bucketsCap
= __CFHashRoundUpCapacity(hc
->_bucketsUsed
+ numNewValues
);
1100 hc
->_bucketsNum
= __CFHashNumBucketsForCapacity(hc
->_bucketsCap
);
1102 CFAllocatorRef allocator
= __CFGetAllocator(hc
);
1103 CFOptionFlags weakOrStrong
= (hc
->_xflags
& __kCFHashWeakKeys
) ? 0 : __kCFAllocatorGCScannedMemory
;
1104 any_t
*mem
= (any_t
*)_CFAllocatorAllocateGC(allocator
, hc
->_bucketsNum
* sizeof(any_t
), weakOrStrong
);
1105 if (NULL
== mem
) __CFDictionaryHandleOutOfMemory(hc
, hc
->_bucketsNum
* sizeof(any_t
));
1106 if (__CFOASafe
) __CFSetLastAllocationEventName(mem
, "CFDictionary (key-store)");
1107 CF_WRITE_BARRIER_BASE_ASSIGN(allocator
, hc
, hc
->_keys
, mem
);
1108 CFAllocatorRef keysAllocator
= (hc
->_xflags
& __kCFHashWeakKeys
) ? kCFAllocatorNull
: allocator
; // GC: avoids write-barrier in weak case.
1109 any_t
*keysBase
= mem
;
1110 #if CFDictionary || CFBag
1111 weakOrStrong
= (hc
->_xflags
& __kCFHashWeakValues
) ? 0 : __kCFAllocatorGCScannedMemory
;
1112 mem
= (any_t
*)_CFAllocatorAllocateGC(allocator
, hc
->_bucketsNum
* sizeof(any_t
), weakOrStrong
);
1113 if (NULL
== mem
) __CFDictionaryHandleOutOfMemory(hc
, hc
->_bucketsNum
* sizeof(any_t
));
1114 if (__CFOASafe
) __CFSetLastAllocationEventName(mem
, "CFDictionary (value-store)");
1115 CF_WRITE_BARRIER_BASE_ASSIGN(allocator
, hc
, hc
->_values
, mem
);
1118 CFAllocatorRef valuesAllocator
= (hc
->_xflags
& __kCFHashWeakValues
) ? kCFAllocatorNull
: allocator
; // GC: avoids write-barrier in weak case.
1119 any_t
*valuesBase
= mem
;
1121 for (CFIndex idx
= 0, nbuckets
= hc
->_bucketsNum
; idx
< nbuckets
; idx
++) {
1122 hc
->_keys
[idx
] = hc
->_marker
;
1123 #if CFDictionary || CFBag
1124 hc
->_values
[idx
] = 0;
1127 if (NULL
== oldkeys
) return;
1128 for (CFIndex idx
= 0; idx
< nbuckets
; idx
++) {
1129 if (__CFHashKeyIsValue(hc
, oldkeys
[idx
])) {
1130 CFIndex match
, nomatch
;
1131 __CFDictionaryFindBuckets2(hc
, oldkeys
[idx
], &match
, &nomatch
);
1132 CFAssert3(kCFNotFound
== match
, __kCFLogAssertion
, "%s(): two values (%p, %p) now hash to the same slot; mutable value changed while in table or hash value is not immutable", __PRETTY_FUNCTION__
, oldkeys
[idx
], hc
->_keys
[match
]);
1133 if (kCFNotFound
!= nomatch
) {
1134 CF_WRITE_BARRIER_BASE_ASSIGN(keysAllocator
, keysBase
, hc
->_keys
[nomatch
], oldkeys
[idx
]);
1136 CF_WRITE_BARRIER_BASE_ASSIGN(valuesAllocator
, valuesBase
, hc
->_values
[nomatch
], oldvalues
[idx
]);
1139 hc
->_values
[nomatch
] = oldvalues
[idx
];
1144 _CFAllocatorDeallocateGC(allocator
, oldkeys
);
1145 _CFAllocatorDeallocateGC(allocator
, oldvalues
);
1148 // This function is for Foundation's benefit; no one else should use it.
1149 void _CFDictionarySetCapacity(CFMutableHashRef hc
, CFIndex cap
) {
1150 if (CF_IS_OBJC(__kCFHashTypeID
, hc
)) return;
1151 __CFGenericValidateType(hc
, __kCFHashTypeID
);
1152 CFAssert1(__CFHashGetType(hc
) != __kCFHashImmutable
, __kCFLogAssertion
, "%s(): collection is immutable", __PRETTY_FUNCTION__
);
1153 CFAssert3(hc
->_bucketsUsed
<= cap
, __kCFLogAssertion
, "%s(): desired capacity (%ld) is less than bucket count (%ld)", __PRETTY_FUNCTION__
, cap
, hc
->_bucketsUsed
);
1154 __CFDictionaryGrow(hc
, cap
- hc
->_bucketsUsed
);
1159 void CFDictionaryAddValue(CFMutableHashRef hc
, const_any_pointer_t key
, const_any_pointer_t value
) {
1162 void CFDictionaryAddValue(CFMutableHashRef hc
, const_any_pointer_t key
) {
1165 if (CFDictionary
) CF_OBJC_FUNCDISPATCH2(__kCFHashTypeID
, void, hc
, "_addObject:forKey:", value
, key
);
1166 if (CFSet
) CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID
, void, hc
, "addObject:", key
);
1167 __CFGenericValidateType(hc
, __kCFHashTypeID
);
1168 switch (__CFHashGetType(hc
)) {
1169 case __kCFHashMutable
:
1170 if (hc
->_bucketsUsed
== hc
->_bucketsCap
|| NULL
== hc
->_keys
) {
1171 __CFDictionaryGrow(hc
, 1);
1175 CFAssert2(__CFHashGetType(hc
) != __kCFHashImmutable
, __kCFLogAssertion
, "%s(): immutable collection %p passed to mutating operation", __PRETTY_FUNCTION__
, hc
);
1179 CFIndex match
, nomatch
;
1180 __CFDictionaryFindBuckets2(hc
, (any_t
)key
, &match
, &nomatch
);
1181 if (kCFNotFound
!= match
) {
1183 CF_OBJC_KVO_WILLCHANGE(hc
, hc
->_keys
[match
]);
1184 hc
->_values
[match
]++;
1186 CF_OBJC_KVO_DIDCHANGE(hc
, hc
->_keys
[match
]);
1189 CFAllocatorRef allocator
= __CFGetAllocator(hc
);
1190 GETNEWKEY(newKey
, key
);
1192 GETNEWVALUE(newValue
);
1194 if (__CFHashKeyIsMagic(hc
, newKey
)) {
1195 __CFDictionaryFindNewMarker(hc
);
1197 if (hc
->_keys
[nomatch
] == ~hc
->_marker
) {
1200 CF_OBJC_KVO_WILLCHANGE(hc
, key
);
1201 CFAllocatorRef keysAllocator
= (hc
->_xflags
& __kCFHashWeakKeys
) ? kCFAllocatorNull
: allocator
;
1202 CF_WRITE_BARRIER_ASSIGN(keysAllocator
, hc
->_keys
[nomatch
], newKey
);
1204 CFAllocatorRef valuesAllocator
= (hc
->_xflags
& __kCFHashWeakValues
) ? kCFAllocatorNull
: allocator
;
1205 CF_WRITE_BARRIER_ASSIGN(valuesAllocator
, hc
->_values
[nomatch
], newValue
);
1208 hc
->_values
[nomatch
] = 1;
1212 CF_OBJC_KVO_DIDCHANGE(hc
, key
);
1217 void CFDictionaryReplaceValue(CFMutableHashRef hc
, const_any_pointer_t key
, const_any_pointer_t value
) {
1220 void CFDictionaryReplaceValue(CFMutableHashRef hc
, const_any_pointer_t key
) {
1223 if (CFDictionary
) CF_OBJC_FUNCDISPATCH2(__kCFHashTypeID
, void, hc
, "_replaceObject:forKey:", value
, key
);
1224 if (CFSet
) CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID
, void, hc
, "_replaceObject:", key
);
1225 __CFGenericValidateType(hc
, __kCFHashTypeID
);
1226 switch (__CFHashGetType(hc
)) {
1227 case __kCFHashMutable
:
1230 CFAssert2(__CFHashGetType(hc
) != __kCFHashImmutable
, __kCFLogAssertion
, "%s(): immutable collection %p passed to mutating operation", __PRETTY_FUNCTION__
, hc
);
1234 if (0 == hc
->_bucketsUsed
) return;
1235 CFIndex match
= __CFDictionaryFindBuckets1(hc
, (any_t
)key
);
1236 if (kCFNotFound
== match
) return;
1237 CFAllocatorRef allocator
= __CFGetAllocator(hc
);
1239 GETNEWKEY(newKey
, key
);
1242 GETNEWVALUE(newValue
);
1244 any_t oldKey
= hc
->_keys
[match
];
1245 CF_OBJC_KVO_WILLCHANGE(hc
, oldKey
);
1247 CFAllocatorRef keysAllocator
= (hc
->_xflags
& __kCFHashWeakKeys
) ? kCFAllocatorNull
: allocator
;
1248 CF_WRITE_BARRIER_ASSIGN(keysAllocator
, hc
->_keys
[match
], ~hc
->_marker
);
1249 if (__CFHashKeyIsMagic(hc
, newKey
)) {
1250 __CFDictionaryFindNewMarker(hc
);
1252 CF_WRITE_BARRIER_ASSIGN(keysAllocator
, hc
->_keys
[match
], newKey
);
1255 any_t oldValue
= hc
->_values
[match
];
1256 CFAllocatorRef valuesAllocator
= (hc
->_xflags
& __kCFHashWeakValues
) ? kCFAllocatorNull
: allocator
;
1257 CF_WRITE_BARRIER_ASSIGN(valuesAllocator
, hc
->_values
[match
], newValue
);
1259 CF_OBJC_KVO_DIDCHANGE(hc
, oldKey
);
1264 RELEASEVALUE(oldValue
);
1269 void CFDictionarySetValue(CFMutableHashRef hc
, const_any_pointer_t key
, const_any_pointer_t value
) {
1272 void CFDictionarySetValue(CFMutableHashRef hc
, const_any_pointer_t key
) {
1275 if (CFDictionary
) CF_OBJC_FUNCDISPATCH2(__kCFHashTypeID
, void, hc
, "setObject:forKey:", value
, key
);
1276 if (CFSet
) CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID
, void, hc
, "_setObject:", key
);
1277 __CFGenericValidateType(hc
, __kCFHashTypeID
);
1278 switch (__CFHashGetType(hc
)) {
1279 case __kCFHashMutable
:
1280 if (hc
->_bucketsUsed
== hc
->_bucketsCap
|| NULL
== hc
->_keys
) {
1281 __CFDictionaryGrow(hc
, 1);
1285 CFAssert2(__CFHashGetType(hc
) != __kCFHashImmutable
, __kCFLogAssertion
, "%s(): immutable collection %p passed to mutating operation", __PRETTY_FUNCTION__
, hc
);
1289 CFIndex match
, nomatch
;
1290 __CFDictionaryFindBuckets2(hc
, (any_t
)key
, &match
, &nomatch
);
1291 if (kCFNotFound
== match
) {
1292 CFAllocatorRef allocator
= __CFGetAllocator(hc
);
1293 GETNEWKEY(newKey
, key
);
1295 GETNEWVALUE(newValue
);
1297 if (__CFHashKeyIsMagic(hc
, newKey
)) {
1298 __CFDictionaryFindNewMarker(hc
);
1300 if (hc
->_keys
[nomatch
] == ~hc
->_marker
) {
1303 CF_OBJC_KVO_WILLCHANGE(hc
, key
);
1304 CFAllocatorRef keysAllocator
= (hc
->_xflags
& __kCFHashWeakKeys
) ? kCFAllocatorNull
: allocator
;
1305 CF_WRITE_BARRIER_ASSIGN(keysAllocator
, hc
->_keys
[nomatch
], newKey
);
1307 CFAllocatorRef valuesAllocator
= (hc
->_xflags
& __kCFHashWeakValues
) ? kCFAllocatorNull
: allocator
;
1308 CF_WRITE_BARRIER_ASSIGN(valuesAllocator
, hc
->_values
[nomatch
], newValue
);
1311 hc
->_values
[nomatch
] = 1;
1315 CF_OBJC_KVO_DIDCHANGE(hc
, key
);
1317 CFAllocatorRef allocator
= __CFGetAllocator(hc
);
1319 GETNEWKEY(newKey
, key
);
1322 GETNEWVALUE(newValue
);
1324 any_t oldKey
= hc
->_keys
[match
];
1325 CF_OBJC_KVO_WILLCHANGE(hc
, oldKey
);
1327 CFAllocatorRef keysAllocator
= (hc
->_xflags
& __kCFHashWeakKeys
) ? kCFAllocatorNull
: allocator
;
1328 CF_WRITE_BARRIER_ASSIGN(keysAllocator
, hc
->_keys
[match
], ~hc
->_marker
);
1329 if (__CFHashKeyIsMagic(hc
, newKey
)) {
1330 __CFDictionaryFindNewMarker(hc
);
1332 CF_WRITE_BARRIER_ASSIGN(keysAllocator
, hc
->_keys
[match
], newKey
);
1335 any_t oldValue
= hc
->_values
[match
];
1336 CFAllocatorRef valuesAllocator
= (hc
->_xflags
& __kCFHashWeakValues
) ? kCFAllocatorNull
: allocator
;
1337 CF_WRITE_BARRIER_ASSIGN(valuesAllocator
, hc
->_values
[match
], newValue
);
1339 CF_OBJC_KVO_DIDCHANGE(hc
, oldKey
);
1344 RELEASEVALUE(oldValue
);
1349 void CFDictionaryRemoveValue(CFMutableHashRef hc
, const_any_pointer_t key
) {
1350 if (CFDictionary
) CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID
, void, hc
, "removeObjectForKey:", key
);
1351 if (CFSet
) CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID
, void, hc
, "removeObject:", key
);
1352 __CFGenericValidateType(hc
, __kCFHashTypeID
);
1353 switch (__CFHashGetType(hc
)) {
1354 case __kCFHashMutable
:
1357 CFAssert2(__CFHashGetType(hc
) != __kCFHashImmutable
, __kCFLogAssertion
, "%s(): immutable collection %p passed to mutating operation", __PRETTY_FUNCTION__
, hc
);
1361 if (0 == hc
->_bucketsUsed
) return;
1362 CFIndex match
= __CFDictionaryFindBuckets1(hc
, (any_t
)key
);
1363 if (kCFNotFound
== match
) return;
1364 if (1 < __CFHashGetOccurrenceCount(hc
, match
)) {
1366 CF_OBJC_KVO_WILLCHANGE(hc
, hc
->_keys
[match
]);
1367 hc
->_values
[match
]--;
1369 CF_OBJC_KVO_DIDCHANGE(hc
, hc
->_keys
[match
]);
1372 CFAllocatorRef allocator
= __CFGetAllocator(hc
);
1373 any_t oldKey
= hc
->_keys
[match
];
1374 CF_OBJC_KVO_WILLCHANGE(hc
, oldKey
);
1375 CFAllocatorRef keysAllocator
= (hc
->_xflags
& __kCFHashWeakKeys
) ? kCFAllocatorNull
: allocator
;
1376 CF_WRITE_BARRIER_ASSIGN(keysAllocator
, hc
->_keys
[match
], ~hc
->_marker
);
1378 any_t oldValue
= hc
->_values
[match
];
1379 CFAllocatorRef valuesAllocator
= (hc
->_xflags
& __kCFHashWeakValues
) ? kCFAllocatorNull
: allocator
;
1380 CF_WRITE_BARRIER_ASSIGN(valuesAllocator
, hc
->_values
[match
], 0);
1383 hc
->_values
[match
] = 0;
1388 CF_OBJC_KVO_DIDCHANGE(hc
, oldKey
);
1391 RELEASEVALUE(oldValue
);
1393 if (__CFDictionaryShouldShrink(hc
)) {
1394 __CFDictionaryGrow(hc
, 0);
1396 // When the probeskip == 1 always and only, a DELETED slot followed by an EMPTY slot
1397 // can be converted to an EMPTY slot. By extension, a chain of DELETED slots followed
1398 // by an EMPTY slot can be converted to EMPTY slots, which is what we do here.
1399 if (match
< hc
->_bucketsNum
- 1 && hc
->_keys
[match
+ 1] == hc
->_marker
) {
1400 while (0 <= match
&& hc
->_keys
[match
] == ~hc
->_marker
) {
1401 hc
->_keys
[match
] = hc
->_marker
;
1410 void CFDictionaryRemoveAllValues(CFMutableHashRef hc
) {
1411 if (CFDictionary
) CF_OBJC_FUNCDISPATCH0(__kCFHashTypeID
, void, hc
, "removeAllObjects");
1412 if (CFSet
) CF_OBJC_FUNCDISPATCH0(__kCFHashTypeID
, void, hc
, "removeAllObjects");
1413 __CFGenericValidateType(hc
, __kCFHashTypeID
);
1414 switch (__CFHashGetType(hc
)) {
1415 case __kCFHashMutable
:
1418 CFAssert2(__CFHashGetType(hc
) != __kCFHashImmutable
, __kCFLogAssertion
, "%s(): immutable collection %p passed to mutating operation", __PRETTY_FUNCTION__
, hc
);
1422 if (0 == hc
->_bucketsUsed
) return;
1423 CFAllocatorRef allocator
= __CFGetAllocator(hc
);
1424 any_t
*keys
= hc
->_keys
;
1425 for (CFIndex idx
= 0, nbuckets
= hc
->_bucketsNum
; idx
< nbuckets
; idx
++) {
1426 if (__CFHashKeyIsValue(hc
, keys
[idx
])) {
1427 any_t oldKey
= keys
[idx
];
1428 CF_OBJC_KVO_WILLCHANGE(hc
, oldKey
);
1429 #if CFDictionary || CFSet
1433 hc
->_count
-= hc
->_values
[idx
];
1435 CFAllocatorRef keysAllocator
= (hc
->_xflags
& __kCFHashWeakKeys
) ? kCFAllocatorNull
: allocator
;
1436 CF_WRITE_BARRIER_ASSIGN(keysAllocator
, hc
->_keys
[idx
], ~hc
->_marker
);
1438 any_t oldValue
= hc
->_values
[idx
];
1439 CFAllocatorRef valuesAllocator
= (hc
->_xflags
& __kCFHashWeakValues
) ? kCFAllocatorNull
: allocator
;
1440 CF_WRITE_BARRIER_ASSIGN(valuesAllocator
, hc
->_values
[idx
], 0);
1443 hc
->_values
[idx
] = 0;
1447 CF_OBJC_KVO_DIDCHANGE(hc
, oldKey
);
1450 RELEASEVALUE(oldValue
);
1454 for (CFIndex idx
= 0, nbuckets
= hc
->_bucketsNum
; idx
< nbuckets
; idx
++) {
1455 keys
[idx
] = hc
->_marker
;
1458 hc
->_bucketsUsed
= 0;
1460 if (__CFDictionaryShouldShrink(hc
) && (256 <= hc
->_bucketsCap
)) {
1461 __CFDictionaryGrow(hc
, 128);
1465 #undef CF_OBJC_KVO_WILLCHANGE
1466 #undef CF_OBJC_KVO_DIDCHANGE