2 * Copyright (c) 2012 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@
25 Copyright (c) 2008-2011, Apple Inc. All rights reserved.
26 Responsibility: Christopher Kane
29 #import "CFBasicHash.h"
30 #import <CoreFoundation/CFRuntime.h>
31 #import <CoreFoundation/CFSet.h>
35 #if DEPLOYMENT_TARGET_WINDOWS
36 #define __SetLastAllocationEventName(A, B) do { } while (0)
38 #define __SetLastAllocationEventName(A, B) do { if (__CFOASafe && (A)) __CFSetLastAllocationEventName(A, B); } while (0)
41 #define GCRETAIN(A, B) kCFTypeSetCallBacks.retain(A, B)
42 #define GCRELEASE(A, B) kCFTypeSetCallBacks.release(A, B)
44 #define __AssignWithWriteBarrier(location, value) objc_assign_strongCast((id)value, (id *)location)
46 #define ENABLE_DTRACE_PROBES 0
47 #define ENABLE_MEMORY_COUNTERS 0
49 #if defined(DTRACE_PROBES_DISABLED) && DTRACE_PROBES_DISABLED
50 #undef ENABLE_DTRACE_PROBES
51 #define ENABLE_DTRACE_PROBES 0
56 // Note: output then changed by casts of the arguments
57 // dtrace macros last generated 2010-09-08 on 10.7 prerelease (11A259)
59 provider Cocoa_HashTable {
60 probe hash_key(unsigned long table, unsigned long key, unsigned long hash);
61 probe test_equal(unsigned long table, unsigned long key1, unsigned long key2);
62 probe probing_start(unsigned long table, unsigned long num_buckets);
63 probe probe_empty(unsigned long table, unsigned long idx);
64 probe probe_deleted(unsigned long table, unsigned long idx);
65 probe probe_valid(unsigned long table, unsigned long idx);
66 probe probing_end(unsigned long table, unsigned long num_probes);
67 probe rehash_start(unsigned long table, unsigned long num_buckets, unsigned long total_size);
68 probe rehash_end(unsigned long table, unsigned long num_buckets, unsigned long total_size);
71 #pragma D attributes Unstable/Unstable/Common provider Cocoa_HashTable provider
72 #pragma D attributes Private/Private/Unknown provider Cocoa_HashTable module
73 #pragma D attributes Private/Private/Unknown provider Cocoa_HashTable function
74 #pragma D attributes Unstable/Unstable/Common provider Cocoa_HashTable name
75 #pragma D attributes Unstable/Unstable/Common provider Cocoa_HashTable args
78 #if ENABLE_DTRACE_PROBES
80 #define COCOA_HASHTABLE_STABILITY "___dtrace_stability$Cocoa_HashTable$v1$4_4_5_1_1_0_1_1_0_4_4_5_4_4_5"
82 #define COCOA_HASHTABLE_TYPEDEFS "___dtrace_typedefs$Cocoa_HashTable$v2"
84 #define COCOA_HASHTABLE_REHASH_END(arg0, arg1, arg2) \
86 __asm__ volatile(".reference " COCOA_HASHTABLE_TYPEDEFS); \
87 __dtrace_probe$Cocoa_HashTable$rehash_end$v1$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67((unsigned long)(arg0), (unsigned long)(arg1), (unsigned long)(arg2)); \
88 __asm__ volatile(".reference " COCOA_HASHTABLE_STABILITY); \
90 #define COCOA_HASHTABLE_REHASH_END_ENABLED() \
91 ({ int _r = __dtrace_isenabled$Cocoa_HashTable$rehash_end$v1(); \
92 __asm__ volatile(""); \
94 #define COCOA_HASHTABLE_REHASH_START(arg0, arg1, arg2) \
96 __asm__ volatile(".reference " COCOA_HASHTABLE_TYPEDEFS); \
97 __dtrace_probe$Cocoa_HashTable$rehash_start$v1$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67((unsigned long)(arg0), (unsigned long)(arg1), (unsigned long)(arg2)); \
98 __asm__ volatile(".reference " COCOA_HASHTABLE_STABILITY); \
100 #define COCOA_HASHTABLE_REHASH_START_ENABLED() \
101 ({ int _r = __dtrace_isenabled$Cocoa_HashTable$rehash_start$v1(); \
102 __asm__ volatile(""); \
104 #define COCOA_HASHTABLE_HASH_KEY(arg0, arg1, arg2) \
106 __asm__ volatile(".reference " COCOA_HASHTABLE_TYPEDEFS); \
107 __dtrace_probe$Cocoa_HashTable$hash_key$v1$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67((unsigned long)(arg0), (unsigned long)(arg1), (unsigned long)(arg2)); \
108 __asm__ volatile(".reference " COCOA_HASHTABLE_STABILITY); \
110 #define COCOA_HASHTABLE_HASH_KEY_ENABLED() \
111 ({ int _r = __dtrace_isenabled$Cocoa_HashTable$hash_key$v1(); \
112 __asm__ volatile(""); \
114 #define COCOA_HASHTABLE_PROBE_DELETED(arg0, arg1) \
116 __asm__ volatile(".reference " COCOA_HASHTABLE_TYPEDEFS); \
117 __dtrace_probe$Cocoa_HashTable$probe_deleted$v1$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67((unsigned long)(arg0), (unsigned long)(arg1)); \
118 __asm__ volatile(".reference " COCOA_HASHTABLE_STABILITY); \
120 #define COCOA_HASHTABLE_PROBE_DELETED_ENABLED() \
121 ({ int _r = __dtrace_isenabled$Cocoa_HashTable$probe_deleted$v1(); \
122 __asm__ volatile(""); \
124 #define COCOA_HASHTABLE_PROBE_EMPTY(arg0, arg1) \
126 __asm__ volatile(".reference " COCOA_HASHTABLE_TYPEDEFS); \
127 __dtrace_probe$Cocoa_HashTable$probe_empty$v1$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67((unsigned long)(arg0), (unsigned long)(arg1)); \
128 __asm__ volatile(".reference " COCOA_HASHTABLE_STABILITY); \
130 #define COCOA_HASHTABLE_PROBE_EMPTY_ENABLED() \
131 ({ int _r = __dtrace_isenabled$Cocoa_HashTable$probe_empty$v1(); \
132 __asm__ volatile(""); \
134 #define COCOA_HASHTABLE_PROBE_VALID(arg0, arg1) \
136 __asm__ volatile(".reference " COCOA_HASHTABLE_TYPEDEFS); \
137 __dtrace_probe$Cocoa_HashTable$probe_valid$v1$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67((unsigned long)(arg0), (unsigned long)(arg1)); \
138 __asm__ volatile(".reference " COCOA_HASHTABLE_STABILITY); \
140 #define COCOA_HASHTABLE_PROBE_VALID_ENABLED() \
141 ({ int _r = __dtrace_isenabled$Cocoa_HashTable$probe_valid$v1(); \
142 __asm__ volatile(""); \
144 #define COCOA_HASHTABLE_PROBING_END(arg0, arg1) \
146 __asm__ volatile(".reference " COCOA_HASHTABLE_TYPEDEFS); \
147 __dtrace_probe$Cocoa_HashTable$probing_end$v1$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67((unsigned long)(arg0), (unsigned long)(arg1)); \
148 __asm__ volatile(".reference " COCOA_HASHTABLE_STABILITY); \
150 #define COCOA_HASHTABLE_PROBING_END_ENABLED() \
151 ({ int _r = __dtrace_isenabled$Cocoa_HashTable$probing_end$v1(); \
152 __asm__ volatile(""); \
154 #define COCOA_HASHTABLE_PROBING_START(arg0, arg1) \
156 __asm__ volatile(".reference " COCOA_HASHTABLE_TYPEDEFS); \
157 __dtrace_probe$Cocoa_HashTable$probing_start$v1$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67((unsigned long)(arg0), (unsigned long)(arg1)); \
158 __asm__ volatile(".reference " COCOA_HASHTABLE_STABILITY); \
160 #define COCOA_HASHTABLE_PROBING_START_ENABLED() \
161 ({ int _r = __dtrace_isenabled$Cocoa_HashTable$probing_start$v1(); \
162 __asm__ volatile(""); \
164 #define COCOA_HASHTABLE_TEST_EQUAL(arg0, arg1, arg2) \
166 __asm__ volatile(".reference " COCOA_HASHTABLE_TYPEDEFS); \
167 __dtrace_probe$Cocoa_HashTable$test_equal$v1$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67((unsigned long)(arg0), (unsigned long)(arg1), (unsigned long)(arg2)); \
168 __asm__ volatile(".reference " COCOA_HASHTABLE_STABILITY); \
170 #define COCOA_HASHTABLE_TEST_EQUAL_ENABLED() \
171 ({ int _r = __dtrace_isenabled$Cocoa_HashTable$test_equal$v1(); \
172 __asm__ volatile(""); \
175 extern void __dtrace_probe$Cocoa_HashTable$hash_key$v1$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67(unsigned long, unsigned long, unsigned long);
176 extern int __dtrace_isenabled$Cocoa_HashTable$hash_key$v1(void);
177 extern void __dtrace_probe$Cocoa_HashTable$probe_deleted$v1$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67(unsigned long, unsigned long);
178 extern int __dtrace_isenabled$Cocoa_HashTable$probe_deleted$v1(void);
179 extern void __dtrace_probe$Cocoa_HashTable$probe_empty$v1$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67(unsigned long, unsigned long);
180 extern int __dtrace_isenabled$Cocoa_HashTable$probe_empty$v1(void);
181 extern void __dtrace_probe$Cocoa_HashTable$probe_valid$v1$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67(unsigned long, unsigned long);
182 extern int __dtrace_isenabled$Cocoa_HashTable$probe_valid$v1(void);
183 extern void __dtrace_probe$Cocoa_HashTable$probing_end$v1$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67(unsigned long, unsigned long);
184 extern int __dtrace_isenabled$Cocoa_HashTable$probing_end$v1(void);
185 extern void __dtrace_probe$Cocoa_HashTable$probing_start$v1$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67(unsigned long, unsigned long);
186 extern int __dtrace_isenabled$Cocoa_HashTable$probing_start$v1(void);
187 extern void __dtrace_probe$Cocoa_HashTable$rehash_end$v1$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67(unsigned long, unsigned long, unsigned long);
188 extern int __dtrace_isenabled$Cocoa_HashTable$rehash_end$v1(void);
189 extern void __dtrace_probe$Cocoa_HashTable$rehash_start$v1$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67(unsigned long, unsigned long, unsigned long);
190 extern int __dtrace_isenabled$Cocoa_HashTable$rehash_start$v1(void);
191 extern void __dtrace_probe$Cocoa_HashTable$test_equal$v1$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67(unsigned long, unsigned long, unsigned long);
192 extern int __dtrace_isenabled$Cocoa_HashTable$test_equal$v1(void);
196 #define COCOA_HASHTABLE_REHASH_END(arg0, arg1, arg2) do {} while (0)
197 #define COCOA_HASHTABLE_REHASH_END_ENABLED() 0
198 #define COCOA_HASHTABLE_REHASH_START(arg0, arg1, arg2) do {} while (0)
199 #define COCOA_HASHTABLE_REHASH_START_ENABLED() 0
200 #define COCOA_HASHTABLE_HASH_KEY(arg0, arg1, arg2) do {} while (0)
201 #define COCOA_HASHTABLE_HASH_KEY_ENABLED() 0
202 #define COCOA_HASHTABLE_PROBE_DELETED(arg0, arg1) do {} while (0)
203 #define COCOA_HASHTABLE_PROBE_DELETED_ENABLED() 0
204 #define COCOA_HASHTABLE_PROBE_EMPTY(arg0, arg1) do {} while (0)
205 #define COCOA_HASHTABLE_PROBE_EMPTY_ENABLED() 0
206 #define COCOA_HASHTABLE_PROBE_VALID(arg0, arg1) do {} while (0)
207 #define COCOA_HASHTABLE_PROBE_VALID_ENABLED() 0
208 #define COCOA_HASHTABLE_PROBING_END(arg0, arg1) do {} while (0)
209 #define COCOA_HASHTABLE_PROBING_END_ENABLED() 0
210 #define COCOA_HASHTABLE_PROBING_START(arg0, arg1) do {} while (0)
211 #define COCOA_HASHTABLE_PROBING_START_ENABLED() 0
212 #define COCOA_HASHTABLE_TEST_EQUAL(arg0, arg1, arg2) do {} while (0)
213 #define COCOA_HASHTABLE_TEST_EQUAL_ENABLED() 0
218 #if !defined(__LP64__)
222 // Prime numbers. Values above 100 have been adjusted up so that the
223 // malloced block size will be just below a multiple of 512; values
224 // above 1200 have been adjusted up to just below a multiple of 4096.
225 static const uintptr_t __CFBasicHashTableSizes[64] = {
226 0, 3, 7, 13, 23, 41, 71, 127, 191, 251, 383, 631, 1087, 1723,
227 2803, 4523, 7351, 11959, 19447, 31231, 50683, 81919, 132607,
228 214519, 346607, 561109, 907759, 1468927, 2376191, 3845119,
229 6221311, 10066421, 16287743, 26354171, 42641881, 68996069,
230 111638519, 180634607, 292272623, 472907251,
232 765180413UL, 1238087663UL, 2003267557UL, 3241355263UL, 5244622819UL,
234 8485977589UL, 13730600407UL, 22216578047UL, 35947178479UL,
235 58163756537UL, 94110934997UL, 152274691561UL, 246385626107UL,
236 398660317687UL, 645045943807UL, 1043706260983UL, 1688752204787UL,
237 2732458465769UL, 4421210670577UL, 7153669136377UL,
238 11574879807461UL, 18728548943849UL, 30303428750843UL
243 static const uintptr_t __CFBasicHashTableCapacities[64] = {
244 0, 3, 6, 11, 19, 32, 52, 85, 118, 155, 237, 390, 672, 1065,
245 1732, 2795, 4543, 7391, 12019, 19302, 31324, 50629, 81956,
246 132580, 214215, 346784, 561026, 907847, 1468567, 2376414,
247 3844982, 6221390, 10066379, 16287773, 26354132, 42641916,
248 68996399, 111638327, 180634415, 292272755,
250 472907503UL, 765180257UL, 1238087439UL, 2003267722UL, 3241355160UL,
252 5244622578UL, 8485977737UL, 13730600347UL, 22216578100UL,
253 35947178453UL, 58163756541UL, 94110935011UL, 152274691274UL,
254 246385626296UL, 398660317578UL, 645045943559UL, 1043706261135UL,
255 1688752204693UL, 2732458465840UL, 4421210670552UL,
256 7153669136706UL, 11574879807265UL, 18728548943682UL
261 // Primitive roots for the primes above
262 static const uintptr_t __CFBasicHashPrimitiveRoots[64] = {
263 0, 2, 3, 2, 5, 6, 7, 3, 19, 6, 5, 3, 3, 3,
264 2, 5, 6, 3, 3, 6, 2, 3, 3,
265 3, 5, 10, 3, 3, 22, 3,
278 CF_INLINE void *__CFBasicHashAllocateMemory(CFConstBasicHashRef ht, CFIndex count, CFIndex elem_size, Boolean strong, Boolean compactable) {
279 CFAllocatorRef allocator = CFGetAllocator(ht);
280 void *new_mem = NULL;
281 if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) {
282 new_mem = auto_zone_allocate_object(objc_collectableZone(), count * elem_size, strong ? (compactable ? AUTO_POINTERS_ONLY : AUTO_MEMORY_SCANNED) : AUTO_UNSCANNED, false, false);
284 new_mem = CFAllocatorAllocate(allocator, count * elem_size, 0);
290 #define __CFBasicHashSubABZero 0xa7baadb1
291 #define __CFBasicHashSubABOne 0xa5baadb9
299 struct __CFBasicHash {
302 uint8_t hash_style:2;
304 uint8_t keys_offset:1;
305 uint8_t counts_offset:2;
306 uint8_t counts_width:2;
307 uint8_t hashes_offset:2;
308 uint8_t strong_values:1;
309 uint8_t strong_keys:1;
310 uint8_t weak_values:1;
312 uint8_t int_values:1;
314 uint8_t indirect_keys:1;
315 uint8_t compactable_keys:1;
316 uint8_t compactable_values:1;
319 uint8_t num_buckets_idx; /* index to number of buckets */
320 uint32_t used_buckets; /* number of used buckets */
323 uint16_t special_bits;
327 __strong CFBasicHashCallbacks *callbacks;
331 __private_extern__ Boolean CFBasicHashHasStrongValues(CFConstBasicHashRef ht) {
335 return ht->bits.strong_values ? true : false;
339 __private_extern__ Boolean CFBasicHashHasStrongKeys(CFConstBasicHashRef ht) {
343 return ht->bits.strong_keys ? true : false;
347 CF_INLINE Boolean __CFBasicHashHasCompactableKeys(CFConstBasicHashRef ht) {
351 return ht->bits.compactable_keys ? true : false;
355 CF_INLINE Boolean __CFBasicHashHasCompactableValues(CFConstBasicHashRef ht) {
359 return ht->bits.compactable_values ? true : false;
363 CF_INLINE Boolean __CFBasicHashHasWeakValues(CFConstBasicHashRef ht) {
367 return ht->bits.weak_values ? true : false;
371 CF_INLINE Boolean __CFBasicHashHasWeakKeys(CFConstBasicHashRef ht) {
375 return ht->bits.weak_keys ? true : false;
379 CF_INLINE Boolean __CFBasicHashHasHashCache(CFConstBasicHashRef ht) {
383 return ht->bits.hashes_offset ? true : false;
387 CF_INLINE uintptr_t __CFBasicHashImportValue(CFConstBasicHashRef ht, uintptr_t stack_value) {
388 return ht->callbacks->retainValue(ht, stack_value);
391 CF_INLINE uintptr_t __CFBasicHashImportKey(CFConstBasicHashRef ht, uintptr_t stack_key) {
392 return ht->callbacks->retainKey(ht, stack_key);
395 CF_INLINE void __CFBasicHashEjectValue(CFConstBasicHashRef ht, uintptr_t stack_value) {
396 ht->callbacks->releaseValue(ht, stack_value);
399 CF_INLINE void __CFBasicHashEjectKey(CFConstBasicHashRef ht, uintptr_t stack_key) {
400 ht->callbacks->releaseKey(ht, stack_key);
403 CF_INLINE Boolean __CFBasicHashTestEqualValue(CFConstBasicHashRef ht, uintptr_t stack_value_a, uintptr_t stack_value_b) {
404 return ht->callbacks->equateValues(ht, stack_value_a, stack_value_b);
407 CF_INLINE Boolean __CFBasicHashTestEqualKey(CFConstBasicHashRef ht, uintptr_t in_coll_key, uintptr_t stack_key) {
408 COCOA_HASHTABLE_TEST_EQUAL(ht, in_coll_key, stack_key);
409 return ht->callbacks->equateKeys(ht, in_coll_key, stack_key);
412 CF_INLINE CFHashCode __CFBasicHashHashKey(CFConstBasicHashRef ht, uintptr_t stack_key) {
413 CFHashCode hash_code = (CFHashCode)ht->callbacks->hashKey(ht, stack_key);
414 COCOA_HASHTABLE_HASH_KEY(ht, stack_key, hash_code);
418 CF_INLINE CFBasicHashValue *__CFBasicHashGetValues(CFConstBasicHashRef ht) {
419 return (CFBasicHashValue *)ht->pointers[0];
422 CF_INLINE void __CFBasicHashSetValues(CFBasicHashRef ht, CFBasicHashValue *ptr) {
423 __AssignWithWriteBarrier(&ht->pointers[0], ptr);
426 CF_INLINE CFBasicHashValue *__CFBasicHashGetKeys(CFConstBasicHashRef ht) {
427 return (CFBasicHashValue *)ht->pointers[ht->bits.keys_offset];
430 CF_INLINE void __CFBasicHashSetKeys(CFBasicHashRef ht, CFBasicHashValue *ptr) {
431 __AssignWithWriteBarrier(&ht->pointers[ht->bits.keys_offset], ptr);
434 CF_INLINE void *__CFBasicHashGetCounts(CFConstBasicHashRef ht) {
435 return (void *)ht->pointers[ht->bits.counts_offset];
438 CF_INLINE void __CFBasicHashSetCounts(CFBasicHashRef ht, void *ptr) {
439 __AssignWithWriteBarrier(&ht->pointers[ht->bits.counts_offset], ptr);
442 CF_INLINE uintptr_t __CFBasicHashGetValue(CFConstBasicHashRef ht, CFIndex idx) {
443 uintptr_t val = __CFBasicHashGetValues(ht)[idx].neutral;
444 if (__CFBasicHashSubABZero == val) return 0UL;
445 if (__CFBasicHashSubABOne == val) return ~0UL;
449 CF_INLINE void __CFBasicHashSetValue(CFBasicHashRef ht, CFIndex idx, uintptr_t stack_value, Boolean ignoreOld, Boolean literal) {
450 CFBasicHashValue *valuep = &(__CFBasicHashGetValues(ht)[idx]);
451 uintptr_t old_value = ignoreOld ? 0 : valuep->neutral;
453 if (0UL == stack_value) stack_value = __CFBasicHashSubABZero;
454 if (~0UL == stack_value) stack_value = __CFBasicHashSubABOne;
456 if (CFBasicHashHasStrongValues(ht)) valuep->strong = (id)stack_value; else valuep->neutral = stack_value;
458 if (!(old_value == 0UL || old_value == ~0UL)) {
459 if (__CFBasicHashSubABZero == old_value) old_value = 0UL;
460 if (__CFBasicHashSubABOne == old_value) old_value = ~0UL;
461 __CFBasicHashEjectValue(ht, old_value);
466 CF_INLINE uintptr_t __CFBasicHashGetKey(CFConstBasicHashRef ht, CFIndex idx) {
467 if (ht->bits.keys_offset) {
468 uintptr_t key = __CFBasicHashGetKeys(ht)[idx].neutral;
469 if (__CFBasicHashSubABZero == key) return 0UL;
470 if (__CFBasicHashSubABOne == key) return ~0UL;
473 if (ht->bits.indirect_keys) {
474 uintptr_t stack_value = __CFBasicHashGetValue(ht, idx);
475 return ht->callbacks->getIndirectKey(ht, stack_value);
477 return __CFBasicHashGetValue(ht, idx);
480 CF_INLINE void __CFBasicHashSetKey(CFBasicHashRef ht, CFIndex idx, uintptr_t stack_key, Boolean ignoreOld, Boolean literal) {
481 if (0 == ht->bits.keys_offset) HALT;
482 CFBasicHashValue *keyp = &(__CFBasicHashGetKeys(ht)[idx]);
483 uintptr_t old_key = ignoreOld ? 0 : keyp->neutral;
485 if (0UL == stack_key) stack_key = __CFBasicHashSubABZero;
486 if (~0UL == stack_key) stack_key = __CFBasicHashSubABOne;
488 if (CFBasicHashHasStrongKeys(ht)) keyp->strong = (id)stack_key; else keyp->neutral = stack_key;
490 if (!(old_key == 0UL || old_key == ~0UL)) {
491 if (__CFBasicHashSubABZero == old_key) old_key = 0UL;
492 if (__CFBasicHashSubABOne == old_key) old_key = ~0UL;
493 __CFBasicHashEjectKey(ht, old_key);
498 CF_INLINE uintptr_t __CFBasicHashIsEmptyOrDeleted(CFConstBasicHashRef ht, CFIndex idx) {
499 uintptr_t stack_value = __CFBasicHashGetValues(ht)[idx].neutral;
500 return (0UL == stack_value || ~0UL == stack_value);
503 CF_INLINE uintptr_t __CFBasicHashIsDeleted(CFConstBasicHashRef ht, CFIndex idx) {
504 uintptr_t stack_value = __CFBasicHashGetValues(ht)[idx].neutral;
505 return (~0UL == stack_value);
508 CF_INLINE uintptr_t __CFBasicHashGetSlotCount(CFConstBasicHashRef ht, CFIndex idx) {
509 void *counts = __CFBasicHashGetCounts(ht);
510 switch (ht->bits.counts_width) {
511 case 0: return ((uint8_t *)counts)[idx];
512 case 1: return ((uint16_t *)counts)[idx];
513 case 2: return ((uint32_t *)counts)[idx];
514 case 3: return ((uint64_t *)counts)[idx];
519 CF_INLINE void __CFBasicHashBumpCounts(CFBasicHashRef ht) {
520 void *counts = __CFBasicHashGetCounts(ht);
521 CFAllocatorRef allocator = CFGetAllocator(ht);
522 switch (ht->bits.counts_width) {
524 uint8_t *counts08 = (uint8_t *)counts;
525 ht->bits.counts_width = 1;
526 CFIndex num_buckets = __CFBasicHashTableSizes[ht->bits.num_buckets_idx];
527 uint16_t *counts16 = (uint16_t *)__CFBasicHashAllocateMemory(ht, num_buckets, 2, false, false);
528 __SetLastAllocationEventName(counts16, "CFBasicHash (count-store)");
529 for (CFIndex idx2 = 0; idx2 < num_buckets; idx2++) {
530 counts16[idx2] = counts08[idx2];
532 __CFBasicHashSetCounts(ht, counts16);
533 if (!CF_IS_COLLECTABLE_ALLOCATOR(allocator)) {
534 CFAllocatorDeallocate(allocator, counts08);
539 uint16_t *counts16 = (uint16_t *)counts;
540 ht->bits.counts_width = 2;
541 CFIndex num_buckets = __CFBasicHashTableSizes[ht->bits.num_buckets_idx];
542 uint32_t *counts32 = (uint32_t *)__CFBasicHashAllocateMemory(ht, num_buckets, 4, false, false);
543 __SetLastAllocationEventName(counts32, "CFBasicHash (count-store)");
544 for (CFIndex idx2 = 0; idx2 < num_buckets; idx2++) {
545 counts32[idx2] = counts16[idx2];
547 __CFBasicHashSetCounts(ht, counts32);
548 if (!CF_IS_COLLECTABLE_ALLOCATOR(allocator)) {
549 CFAllocatorDeallocate(allocator, counts16);
554 uint32_t *counts32 = (uint32_t *)counts;
555 ht->bits.counts_width = 3;
556 CFIndex num_buckets = __CFBasicHashTableSizes[ht->bits.num_buckets_idx];
557 uint64_t *counts64 = (uint64_t *)__CFBasicHashAllocateMemory(ht, num_buckets, 8, false, false);
558 __SetLastAllocationEventName(counts64, "CFBasicHash (count-store)");
559 for (CFIndex idx2 = 0; idx2 < num_buckets; idx2++) {
560 counts64[idx2] = counts32[idx2];
562 __CFBasicHashSetCounts(ht, counts64);
563 if (!CF_IS_COLLECTABLE_ALLOCATOR(allocator)) {
564 CFAllocatorDeallocate(allocator, counts32);
575 static void __CFBasicHashIncSlotCount(CFBasicHashRef ht, CFIndex idx) {
576 void *counts = __CFBasicHashGetCounts(ht);
577 switch (ht->bits.counts_width) {
579 uint8_t *counts08 = (uint8_t *)counts;
580 uint8_t val = counts08[idx];
581 if (val < INT8_MAX) {
582 counts08[idx] = val + 1;
585 __CFBasicHashBumpCounts(ht);
586 __CFBasicHashIncSlotCount(ht, idx);
590 uint16_t *counts16 = (uint16_t *)counts;
591 uint16_t val = counts16[idx];
592 if (val < INT16_MAX) {
593 counts16[idx] = val + 1;
596 __CFBasicHashBumpCounts(ht);
597 __CFBasicHashIncSlotCount(ht, idx);
601 uint32_t *counts32 = (uint32_t *)counts;
602 uint32_t val = counts32[idx];
603 if (val < INT32_MAX) {
604 counts32[idx] = val + 1;
607 __CFBasicHashBumpCounts(ht);
608 __CFBasicHashIncSlotCount(ht, idx);
612 uint64_t *counts64 = (uint64_t *)counts;
613 uint64_t val = counts64[idx];
614 if (val < INT64_MAX) {
615 counts64[idx] = val + 1;
618 __CFBasicHashBumpCounts(ht);
619 __CFBasicHashIncSlotCount(ht, idx);
625 CF_INLINE void __CFBasicHashDecSlotCount(CFBasicHashRef ht, CFIndex idx) {
626 void *counts = __CFBasicHashGetCounts(ht);
627 switch (ht->bits.counts_width) {
628 case 0: ((uint8_t *)counts)[idx]--; return;
629 case 1: ((uint16_t *)counts)[idx]--; return;
630 case 2: ((uint32_t *)counts)[idx]--; return;
631 case 3: ((uint64_t *)counts)[idx]--; return;
635 CF_INLINE uintptr_t *__CFBasicHashGetHashes(CFConstBasicHashRef ht) {
636 return (uintptr_t *)ht->pointers[ht->bits.hashes_offset];
639 CF_INLINE void __CFBasicHashSetHashes(CFBasicHashRef ht, uintptr_t *ptr) {
640 __AssignWithWriteBarrier(&ht->pointers[ht->bits.hashes_offset], ptr);
644 // to expose the load factor, expose this function to customization
645 CF_INLINE CFIndex __CFBasicHashGetCapacityForNumBuckets(CFConstBasicHashRef ht, CFIndex num_buckets_idx) {
646 return __CFBasicHashTableCapacities[num_buckets_idx];
649 CF_INLINE CFIndex __CFBasicHashGetNumBucketsIndexForCapacity(CFConstBasicHashRef ht, CFIndex capacity) {
650 for (CFIndex idx = 0; idx < 64; idx++) {
651 if (capacity <= __CFBasicHashGetCapacityForNumBuckets(ht, idx)) return idx;
657 __private_extern__ CFIndex CFBasicHashGetNumBuckets(CFConstBasicHashRef ht) {
658 return __CFBasicHashTableSizes[ht->bits.num_buckets_idx];
661 __private_extern__ CFIndex CFBasicHashGetCapacity(CFConstBasicHashRef ht) {
662 return __CFBasicHashGetCapacityForNumBuckets(ht, ht->bits.num_buckets_idx);
665 // In returned struct, .count is zero if the bucket is empty or deleted,
666 // and the .weak_key field indicates which. .idx is either the index of
667 // the found bucket or the index of the bucket which should be filled by
668 // an add operation. For a set or multiset, the .weak_key and .weak_value
670 __private_extern__ CFBasicHashBucket CFBasicHashGetBucket(CFConstBasicHashRef ht, CFIndex idx) {
671 CFBasicHashBucket result;
673 if (__CFBasicHashIsEmptyOrDeleted(ht, idx)) {
675 result.weak_value = 0;
678 result.count = (ht->bits.counts_offset) ? __CFBasicHashGetSlotCount(ht, idx) : 1;
679 result.weak_value = __CFBasicHashGetValue(ht, idx);
680 result.weak_key = __CFBasicHashGetKey(ht, idx);
686 static uintptr_t __CFBasicHashFold(uintptr_t dividend, uint8_t idx) {
688 case 1: return dividend % 3;
689 case 2: return dividend % 7;
690 case 3: return dividend % 13;
691 case 4: return dividend % 23;
692 case 5: return dividend % 41;
693 case 6: return dividend % 71;
694 case 7: return dividend % 127;
695 case 8: return dividend % 191;
696 case 9: return dividend % 251;
697 case 10: return dividend % 383;
698 case 11: return dividend % 631;
699 case 12: return dividend % 1087;
700 case 13: return dividend % 1723;
701 case 14: return dividend % 2803;
702 case 15: return dividend % 4523;
703 case 16: return dividend % 7351;
704 case 17: return dividend % 11959;
705 case 18: return dividend % 19447;
706 case 19: return dividend % 31231;
707 case 20: return dividend % 50683;
708 case 21: return dividend % 81919;
709 case 22: return dividend % 132607;
710 case 23: return dividend % 214519;
711 case 24: return dividend % 346607;
712 case 25: return dividend % 561109;
713 case 26: return dividend % 907759;
714 case 27: return dividend % 1468927;
715 case 28: return dividend % 2376191;
716 case 29: return dividend % 3845119;
717 case 30: return dividend % 6221311;
718 case 31: return dividend % 10066421;
719 case 32: return dividend % 16287743;
720 case 33: return dividend % 26354171;
721 case 34: return dividend % 42641881;
722 case 35: return dividend % 68996069;
723 case 36: return dividend % 111638519;
724 case 37: return dividend % 180634607;
725 case 38: return dividend % 292272623;
726 case 39: return dividend % 472907251;
734 #define FIND_BUCKET_NAME ___CFBasicHashFindBucket_Linear
735 #define FIND_BUCKET_HASH_STYLE 1
736 #define FIND_BUCKET_FOR_REHASH 0
737 #define FIND_BUCKET_FOR_INDIRECT_KEY 0
738 #include "CFBasicHashFindBucket.m"
740 #define FIND_BUCKET_NAME ___CFBasicHashFindBucket_Linear_NoCollision
741 #define FIND_BUCKET_HASH_STYLE 1
742 #define FIND_BUCKET_FOR_REHASH 1
743 #define FIND_BUCKET_FOR_INDIRECT_KEY 0
744 #include "CFBasicHashFindBucket.m"
746 #define FIND_BUCKET_NAME ___CFBasicHashFindBucket_Linear_Indirect
747 #define FIND_BUCKET_HASH_STYLE 1
748 #define FIND_BUCKET_FOR_REHASH 0
749 #define FIND_BUCKET_FOR_INDIRECT_KEY 1
750 #include "CFBasicHashFindBucket.m"
752 #define FIND_BUCKET_NAME ___CFBasicHashFindBucket_Linear_Indirect_NoCollision
753 #define FIND_BUCKET_HASH_STYLE 1
754 #define FIND_BUCKET_FOR_REHASH 1
755 #define FIND_BUCKET_FOR_INDIRECT_KEY 1
756 #include "CFBasicHashFindBucket.m"
758 #define FIND_BUCKET_NAME ___CFBasicHashFindBucket_Double
759 #define FIND_BUCKET_HASH_STYLE 2
760 #define FIND_BUCKET_FOR_REHASH 0
761 #define FIND_BUCKET_FOR_INDIRECT_KEY 0
762 #include "CFBasicHashFindBucket.m"
764 #define FIND_BUCKET_NAME ___CFBasicHashFindBucket_Double_NoCollision
765 #define FIND_BUCKET_HASH_STYLE 2
766 #define FIND_BUCKET_FOR_REHASH 1
767 #define FIND_BUCKET_FOR_INDIRECT_KEY 0
768 #include "CFBasicHashFindBucket.m"
770 #define FIND_BUCKET_NAME ___CFBasicHashFindBucket_Double_Indirect
771 #define FIND_BUCKET_HASH_STYLE 2
772 #define FIND_BUCKET_FOR_REHASH 0
773 #define FIND_BUCKET_FOR_INDIRECT_KEY 1
774 #include "CFBasicHashFindBucket.m"
776 #define FIND_BUCKET_NAME ___CFBasicHashFindBucket_Double_Indirect_NoCollision
777 #define FIND_BUCKET_HASH_STYLE 2
778 #define FIND_BUCKET_FOR_REHASH 1
779 #define FIND_BUCKET_FOR_INDIRECT_KEY 1
780 #include "CFBasicHashFindBucket.m"
782 #define FIND_BUCKET_NAME ___CFBasicHashFindBucket_Exponential
783 #define FIND_BUCKET_HASH_STYLE 3
784 #define FIND_BUCKET_FOR_REHASH 0
785 #define FIND_BUCKET_FOR_INDIRECT_KEY 0
786 #include "CFBasicHashFindBucket.m"
788 #define FIND_BUCKET_NAME ___CFBasicHashFindBucket_Exponential_NoCollision
789 #define FIND_BUCKET_HASH_STYLE 3
790 #define FIND_BUCKET_FOR_REHASH 1
791 #define FIND_BUCKET_FOR_INDIRECT_KEY 0
792 #include "CFBasicHashFindBucket.m"
794 #define FIND_BUCKET_NAME ___CFBasicHashFindBucket_Exponential_Indirect
795 #define FIND_BUCKET_HASH_STYLE 3
796 #define FIND_BUCKET_FOR_REHASH 0
797 #define FIND_BUCKET_FOR_INDIRECT_KEY 1
798 #include "CFBasicHashFindBucket.m"
800 #define FIND_BUCKET_NAME ___CFBasicHashFindBucket_Exponential_Indirect_NoCollision
801 #define FIND_BUCKET_HASH_STYLE 3
802 #define FIND_BUCKET_FOR_REHASH 1
803 #define FIND_BUCKET_FOR_INDIRECT_KEY 1
804 #include "CFBasicHashFindBucket.m"
807 CF_INLINE CFBasicHashBucket __CFBasicHashFindBucket(CFConstBasicHashRef ht, uintptr_t stack_key) {
808 if (0 == ht->bits.num_buckets_idx) {
809 CFBasicHashBucket result = {kCFNotFound, 0UL, 0UL, 0};
812 if (ht->bits.indirect_keys) {
813 switch (ht->bits.hash_style) {
814 case __kCFBasicHashLinearHashingValue: return ___CFBasicHashFindBucket_Linear_Indirect(ht, stack_key);
815 case __kCFBasicHashDoubleHashingValue: return ___CFBasicHashFindBucket_Double_Indirect(ht, stack_key);
816 case __kCFBasicHashExponentialHashingValue: return ___CFBasicHashFindBucket_Exponential_Indirect(ht, stack_key);
819 switch (ht->bits.hash_style) {
820 case __kCFBasicHashLinearHashingValue: return ___CFBasicHashFindBucket_Linear(ht, stack_key);
821 case __kCFBasicHashDoubleHashingValue: return ___CFBasicHashFindBucket_Double(ht, stack_key);
822 case __kCFBasicHashExponentialHashingValue: return ___CFBasicHashFindBucket_Exponential(ht, stack_key);
826 CFBasicHashBucket result = {kCFNotFound, 0UL, 0UL, 0};
830 CF_INLINE CFIndex __CFBasicHashFindBucket_NoCollision(CFConstBasicHashRef ht, uintptr_t stack_key, uintptr_t key_hash) {
831 if (0 == ht->bits.num_buckets_idx) {
834 if (ht->bits.indirect_keys) {
835 switch (ht->bits.hash_style) {
836 case __kCFBasicHashLinearHashingValue: return ___CFBasicHashFindBucket_Linear_Indirect_NoCollision(ht, stack_key, key_hash);
837 case __kCFBasicHashDoubleHashingValue: return ___CFBasicHashFindBucket_Double_Indirect_NoCollision(ht, stack_key, key_hash);
838 case __kCFBasicHashExponentialHashingValue: return ___CFBasicHashFindBucket_Exponential_Indirect_NoCollision(ht, stack_key, key_hash);
841 switch (ht->bits.hash_style) {
842 case __kCFBasicHashLinearHashingValue: return ___CFBasicHashFindBucket_Linear_NoCollision(ht, stack_key, key_hash);
843 case __kCFBasicHashDoubleHashingValue: return ___CFBasicHashFindBucket_Double_NoCollision(ht, stack_key, key_hash);
844 case __kCFBasicHashExponentialHashingValue: return ___CFBasicHashFindBucket_Exponential_NoCollision(ht, stack_key, key_hash);
851 __private_extern__ CFBasicHashBucket CFBasicHashFindBucket(CFConstBasicHashRef ht, uintptr_t stack_key) {
852 if (__CFBasicHashSubABZero == stack_key || __CFBasicHashSubABOne == stack_key) {
853 CFBasicHashBucket result = {kCFNotFound, 0UL, 0UL, 0};
856 return __CFBasicHashFindBucket(ht, stack_key);
859 __private_extern__ uint16_t CFBasicHashGetSpecialBits(CFConstBasicHashRef ht) {
860 return ht->bits.special_bits;
863 __private_extern__ uint16_t CFBasicHashSetSpecialBits(CFBasicHashRef ht, uint16_t bits) {
864 uint16_t old = ht->bits.special_bits;
865 ht->bits.special_bits = bits;
869 __private_extern__ CFOptionFlags CFBasicHashGetFlags(CFConstBasicHashRef ht) {
870 CFOptionFlags flags = (ht->bits.hash_style << 13);
871 if (CFBasicHashHasStrongValues(ht)) flags |= kCFBasicHashStrongValues;
872 if (CFBasicHashHasStrongKeys(ht)) flags |= kCFBasicHashStrongKeys;
873 if (__CFBasicHashHasCompactableKeys(ht)) flags |= kCFBasicHashCompactableKeys;
874 if (__CFBasicHashHasCompactableValues(ht)) flags |= kCFBasicHashCompactableValues;
875 if (ht->bits.fast_grow) flags |= kCFBasicHashAggressiveGrowth;
876 if (ht->bits.keys_offset) flags |= kCFBasicHashHasKeys;
877 if (ht->bits.counts_offset) flags |= kCFBasicHashHasCounts;
878 if (__CFBasicHashHasHashCache(ht)) flags |= kCFBasicHashHasHashCache;
882 __private_extern__ const CFBasicHashCallbacks *CFBasicHashGetCallbacks(CFConstBasicHashRef ht) {
883 return ht->callbacks;
886 __private_extern__ CFIndex CFBasicHashGetCount(CFConstBasicHashRef ht) {
887 if (ht->bits.counts_offset) {
889 CFIndex cnt = (CFIndex)__CFBasicHashTableSizes[ht->bits.num_buckets_idx];
890 for (CFIndex idx = 0; idx < cnt; idx++) {
891 total += __CFBasicHashGetSlotCount(ht, idx);
895 return (CFIndex)ht->bits.used_buckets;
898 __private_extern__ CFIndex CFBasicHashGetCountOfKey(CFConstBasicHashRef ht, uintptr_t stack_key) {
899 if (__CFBasicHashSubABZero == stack_key || __CFBasicHashSubABOne == stack_key) {
902 if (0L == ht->bits.used_buckets) {
905 return __CFBasicHashFindBucket(ht, stack_key).count;
908 __private_extern__ CFIndex CFBasicHashGetCountOfValue(CFConstBasicHashRef ht, uintptr_t stack_value) {
909 if (__CFBasicHashSubABZero == stack_value) {
912 if (0L == ht->bits.used_buckets) {
915 if (!(ht->bits.keys_offset)) {
916 return __CFBasicHashFindBucket(ht, stack_value).count;
918 __block CFIndex total = 0L;
919 CFBasicHashApply(ht, ^(CFBasicHashBucket bkt) {
920 if ((stack_value == bkt.weak_value) || __CFBasicHashTestEqualValue(ht, bkt.weak_value, stack_value)) total += bkt.count;
921 return (Boolean)true;
926 __private_extern__ Boolean CFBasicHashesAreEqual(CFConstBasicHashRef ht1, CFConstBasicHashRef ht2) {
927 CFIndex cnt1 = CFBasicHashGetCount(ht1);
928 if (cnt1 != CFBasicHashGetCount(ht2)) return false;
929 if (0 == cnt1) return true;
930 __block Boolean equal = true;
931 CFBasicHashApply(ht1, ^(CFBasicHashBucket bkt1) {
932 CFBasicHashBucket bkt2 = __CFBasicHashFindBucket(ht2, bkt1.weak_key);
933 if (bkt1.count != bkt2.count) {
935 return (Boolean)false;
937 if ((ht1->bits.keys_offset) && (bkt1.weak_value != bkt2.weak_value) && !__CFBasicHashTestEqualValue(ht1, bkt1.weak_value, bkt2.weak_value)) {
939 return (Boolean)false;
941 return (Boolean)true;
946 __private_extern__ void CFBasicHashApply(CFConstBasicHashRef ht, Boolean (^block)(CFBasicHashBucket)) {
947 CFIndex used = (CFIndex)ht->bits.used_buckets, cnt = (CFIndex)__CFBasicHashTableSizes[ht->bits.num_buckets_idx];
948 for (CFIndex idx = 0; 0 < used && idx < cnt; idx++) {
949 CFBasicHashBucket bkt = CFBasicHashGetBucket(ht, idx);
959 __private_extern__ void CFBasicHashApplyIndexed(CFConstBasicHashRef ht, CFRange range, Boolean (^block)(CFBasicHashBucket)) {
960 if (range.length < 0) HALT;
961 if (range.length == 0) return;
962 CFIndex cnt = (CFIndex)__CFBasicHashTableSizes[ht->bits.num_buckets_idx];
963 if (cnt < range.location + range.length) HALT;
964 for (CFIndex idx = 0; idx < range.length; idx++) {
965 CFBasicHashBucket bkt = CFBasicHashGetBucket(ht, range.location + idx);
974 __private_extern__ void CFBasicHashGetElements(CFConstBasicHashRef ht, CFIndex bufferslen, uintptr_t *weak_values, uintptr_t *weak_keys) {
975 CFIndex used = (CFIndex)ht->bits.used_buckets, cnt = (CFIndex)__CFBasicHashTableSizes[ht->bits.num_buckets_idx];
977 for (CFIndex idx = 0; 0 < used && idx < cnt && offset < bufferslen; idx++) {
978 CFBasicHashBucket bkt = CFBasicHashGetBucket(ht, idx);
981 for (CFIndex cnt = bkt.count; cnt-- && offset < bufferslen;) {
982 if (weak_values) { weak_values[offset] = bkt.weak_value; }
983 if (weak_keys) { weak_keys[offset] = bkt.weak_key; }
990 __private_extern__ unsigned long __CFBasicHashFastEnumeration(CFConstBasicHashRef ht, struct __objcFastEnumerationStateEquivalent2 *state, void *stackbuffer, unsigned long count) {
991 /* copy as many as count items over */
992 if (0 == state->state) { /* first time */
993 state->mutationsPtr = (unsigned long *)&ht->bits + (__LP64__ ? 1 : 3);
995 state->itemsPtr = (unsigned long *)stackbuffer;
997 CFIndex used = (CFIndex)ht->bits.used_buckets, cnt = (CFIndex)__CFBasicHashTableSizes[ht->bits.num_buckets_idx];
998 for (CFIndex idx = (CFIndex)state->state; 0 < used && idx < cnt && cntx < (CFIndex)count; idx++) {
999 CFBasicHashBucket bkt = CFBasicHashGetBucket(ht, idx);
1000 if (0 < bkt.count) {
1001 state->itemsPtr[cntx++] = (unsigned long)bkt.weak_key;
1009 #if ENABLE_MEMORY_COUNTERS
1010 static volatile int64_t __CFBasicHashTotalCount = 0ULL;
1011 static volatile int64_t __CFBasicHashTotalSize = 0ULL;
1012 static volatile int64_t __CFBasicHashPeakCount = 0ULL;
1013 static volatile int64_t __CFBasicHashPeakSize = 0ULL;
1014 static volatile int32_t __CFBasicHashSizes[64] = {0};
1017 static void __CFBasicHashDrain(CFBasicHashRef ht, Boolean forFinalization) {
1018 #if ENABLE_MEMORY_COUNTERS
1019 OSAtomicAdd64Barrier(-1 * (int64_t) CFBasicHashGetSize(ht, true), & __CFBasicHashTotalSize);
1022 CFIndex old_num_buckets = __CFBasicHashTableSizes[ht->bits.num_buckets_idx];
1024 CFAllocatorRef allocator = CFGetAllocator(ht);
1025 Boolean nullify = (!forFinalization || !CF_IS_COLLECTABLE_ALLOCATOR(allocator));
1027 CFBasicHashValue *old_values = NULL, *old_keys = NULL;
1028 void *old_counts = NULL;
1029 uintptr_t *old_hashes = NULL;
1031 old_values = __CFBasicHashGetValues(ht);
1032 if (nullify) __CFBasicHashSetValues(ht, NULL);
1033 if (ht->bits.keys_offset) {
1034 old_keys = __CFBasicHashGetKeys(ht);
1035 if (nullify) __CFBasicHashSetKeys(ht, NULL);
1037 if (ht->bits.counts_offset) {
1038 old_counts = __CFBasicHashGetCounts(ht);
1039 if (nullify) __CFBasicHashSetCounts(ht, NULL);
1041 if (__CFBasicHashHasHashCache(ht)) {
1042 old_hashes = __CFBasicHashGetHashes(ht);
1043 if (nullify) __CFBasicHashSetHashes(ht, NULL);
1047 ht->bits.mutations++;
1048 ht->bits.num_buckets_idx = 0;
1049 ht->bits.used_buckets = 0;
1050 ht->bits.deleted = 0;
1053 for (CFIndex idx = 0; idx < old_num_buckets; idx++) {
1054 uintptr_t stack_value = old_values[idx].neutral;
1055 if (stack_value != 0UL && stack_value != ~0UL) {
1056 uintptr_t old_value = stack_value;
1057 if (__CFBasicHashSubABZero == old_value) old_value = 0UL;
1058 if (__CFBasicHashSubABOne == old_value) old_value = ~0UL;
1059 __CFBasicHashEjectValue(ht, old_value);
1061 uintptr_t old_key = old_keys[idx].neutral;
1062 if (__CFBasicHashSubABZero == old_key) old_key = 0UL;
1063 if (__CFBasicHashSubABOne == old_key) old_key = ~0UL;
1064 __CFBasicHashEjectKey(ht, old_key);
1069 if (forFinalization) {
1070 ht->callbacks->freeCallbacks(ht, allocator, ht->callbacks);
1073 if (!CF_IS_COLLECTABLE_ALLOCATOR(allocator)) {
1074 CFAllocatorDeallocate(allocator, old_values);
1075 CFAllocatorDeallocate(allocator, old_keys);
1076 CFAllocatorDeallocate(allocator, old_counts);
1077 CFAllocatorDeallocate(allocator, old_hashes);
1080 #if ENABLE_MEMORY_COUNTERS
1081 int64_t size_now = OSAtomicAdd64Barrier((int64_t) CFBasicHashGetSize(ht, true), & __CFBasicHashTotalSize);
1082 while (__CFBasicHashPeakSize < size_now && !OSAtomicCompareAndSwap64Barrier(__CFBasicHashPeakSize, size_now, & __CFBasicHashPeakSize));
1086 static void __CFBasicHashRehash(CFBasicHashRef ht, CFIndex newItemCount) {
1087 #if ENABLE_MEMORY_COUNTERS
1088 OSAtomicAdd64Barrier(-1 * (int64_t) CFBasicHashGetSize(ht, true), & __CFBasicHashTotalSize);
1089 OSAtomicAdd32Barrier(-1, &__CFBasicHashSizes[ht->bits.num_buckets_idx]);
1092 if (COCOA_HASHTABLE_REHASH_START_ENABLED()) COCOA_HASHTABLE_REHASH_START(ht, CFBasicHashGetNumBuckets(ht), CFBasicHashGetSize(ht, true));
1094 CFIndex new_num_buckets_idx = ht->bits.num_buckets_idx;
1095 if (0 != newItemCount) {
1096 if (newItemCount < 0) newItemCount = 0;
1097 CFIndex new_capacity_req = ht->bits.used_buckets + newItemCount;
1098 new_num_buckets_idx = __CFBasicHashGetNumBucketsIndexForCapacity(ht, new_capacity_req);
1099 if (1 == newItemCount && ht->bits.fast_grow) {
1100 new_num_buckets_idx++;
1104 CFIndex new_num_buckets = __CFBasicHashTableSizes[new_num_buckets_idx];
1105 CFIndex old_num_buckets = __CFBasicHashTableSizes[ht->bits.num_buckets_idx];
1107 CFBasicHashValue *new_values = NULL, *new_keys = NULL;
1108 void *new_counts = NULL;
1109 uintptr_t *new_hashes = NULL;
1111 if (0 < new_num_buckets) {
1112 new_values = (CFBasicHashValue *)__CFBasicHashAllocateMemory(ht, new_num_buckets, sizeof(CFBasicHashValue), CFBasicHashHasStrongValues(ht), __CFBasicHashHasCompactableValues(ht));
1113 __SetLastAllocationEventName(new_values, "CFBasicHash (value-store)");
1114 memset(new_values, 0, new_num_buckets * sizeof(CFBasicHashValue));
1115 if (ht->bits.keys_offset) {
1116 new_keys = (CFBasicHashValue *)__CFBasicHashAllocateMemory(ht, new_num_buckets, sizeof(CFBasicHashValue), CFBasicHashHasStrongKeys(ht), __CFBasicHashHasCompactableKeys(ht));
1117 __SetLastAllocationEventName(new_keys, "CFBasicHash (key-store)");
1118 memset(new_keys, 0, new_num_buckets * sizeof(CFBasicHashValue));
1120 if (ht->bits.counts_offset) {
1121 new_counts = (uintptr_t *)__CFBasicHashAllocateMemory(ht, new_num_buckets, (1 << ht->bits.counts_width), false, false);
1122 __SetLastAllocationEventName(new_counts, "CFBasicHash (count-store)");
1123 memset(new_counts, 0, new_num_buckets * (1 << ht->bits.counts_width));
1125 if (__CFBasicHashHasHashCache(ht)) {
1126 new_hashes = (uintptr_t *)__CFBasicHashAllocateMemory(ht, new_num_buckets, sizeof(uintptr_t), false, false);
1127 __SetLastAllocationEventName(new_hashes, "CFBasicHash (hash-store)");
1128 memset(new_hashes, 0, new_num_buckets * sizeof(uintptr_t));
1132 ht->bits.num_buckets_idx = new_num_buckets_idx;
1133 ht->bits.deleted = 0;
1135 CFBasicHashValue *old_values = NULL, *old_keys = NULL;
1136 void *old_counts = NULL;
1137 uintptr_t *old_hashes = NULL;
1139 old_values = __CFBasicHashGetValues(ht);
1140 __CFBasicHashSetValues(ht, new_values);
1141 if (ht->bits.keys_offset) {
1142 old_keys = __CFBasicHashGetKeys(ht);
1143 __CFBasicHashSetKeys(ht, new_keys);
1145 if (ht->bits.counts_offset) {
1146 old_counts = __CFBasicHashGetCounts(ht);
1147 __CFBasicHashSetCounts(ht, new_counts);
1149 if (__CFBasicHashHasHashCache(ht)) {
1150 old_hashes = __CFBasicHashGetHashes(ht);
1151 __CFBasicHashSetHashes(ht, new_hashes);
1154 if (0 < old_num_buckets) {
1155 for (CFIndex idx = 0; idx < old_num_buckets; idx++) {
1156 uintptr_t stack_value = old_values[idx].neutral;
1157 if (stack_value != 0UL && stack_value != ~0UL) {
1158 if (__CFBasicHashSubABZero == stack_value) stack_value = 0UL;
1159 if (__CFBasicHashSubABOne == stack_value) stack_value = ~0UL;
1160 uintptr_t stack_key = stack_value;
1161 if (ht->bits.keys_offset) {
1162 stack_key = old_keys[idx].neutral;
1163 if (__CFBasicHashSubABZero == stack_key) stack_key = 0UL;
1164 if (__CFBasicHashSubABOne == stack_key) stack_key = ~0UL;
1166 if (ht->bits.indirect_keys) {
1167 stack_key = ht->callbacks->getIndirectKey(ht, stack_value);
1169 CFIndex bkt_idx = __CFBasicHashFindBucket_NoCollision(ht, stack_key, old_hashes ? old_hashes[idx] : 0UL);
1170 __CFBasicHashSetValue(ht, bkt_idx, stack_value, false, false);
1172 __CFBasicHashSetKey(ht, bkt_idx, stack_key, false, false);
1175 switch (ht->bits.counts_width) {
1176 case 0: ((uint8_t *)new_counts)[bkt_idx] = ((uint8_t *)old_counts)[idx]; break;
1177 case 1: ((uint16_t *)new_counts)[bkt_idx] = ((uint16_t *)old_counts)[idx]; break;
1178 case 2: ((uint32_t *)new_counts)[bkt_idx] = ((uint32_t *)old_counts)[idx]; break;
1179 case 3: ((uint64_t *)new_counts)[bkt_idx] = ((uint64_t *)old_counts)[idx]; break;
1183 new_hashes[bkt_idx] = old_hashes[idx];
1189 CFAllocatorRef allocator = CFGetAllocator(ht);
1190 if (!CF_IS_COLLECTABLE_ALLOCATOR(allocator)) {
1191 CFAllocatorDeallocate(allocator, old_values);
1192 CFAllocatorDeallocate(allocator, old_keys);
1193 CFAllocatorDeallocate(allocator, old_counts);
1194 CFAllocatorDeallocate(allocator, old_hashes);
1197 if (COCOA_HASHTABLE_REHASH_END_ENABLED()) COCOA_HASHTABLE_REHASH_END(ht, CFBasicHashGetNumBuckets(ht), CFBasicHashGetSize(ht, true));
1199 #if ENABLE_MEMORY_COUNTERS
1200 int64_t size_now = OSAtomicAdd64Barrier((int64_t) CFBasicHashGetSize(ht, true), &__CFBasicHashTotalSize);
1201 while (__CFBasicHashPeakSize < size_now && !OSAtomicCompareAndSwap64Barrier(__CFBasicHashPeakSize, size_now, & __CFBasicHashPeakSize));
1202 OSAtomicAdd32Barrier(1, &__CFBasicHashSizes[ht->bits.num_buckets_idx]);
1206 __private_extern__ void CFBasicHashSetCapacity(CFBasicHashRef ht, CFIndex capacity) {
1207 if (!CFBasicHashIsMutable(ht)) HALT;
1208 if (ht->bits.used_buckets < capacity) {
1209 ht->bits.mutations++;
1210 __CFBasicHashRehash(ht, capacity - ht->bits.used_buckets);
1214 static void __CFBasicHashAddValue(CFBasicHashRef ht, CFIndex bkt_idx, uintptr_t stack_key, uintptr_t stack_value) {
1215 ht->bits.mutations++;
1216 if (CFBasicHashGetCapacity(ht) < ht->bits.used_buckets + 1) {
1217 __CFBasicHashRehash(ht, 1);
1218 bkt_idx = __CFBasicHashFindBucket_NoCollision(ht, stack_key, 0);
1219 } else if (__CFBasicHashIsDeleted(ht, bkt_idx)) {
1222 uintptr_t key_hash = 0;
1223 if (__CFBasicHashHasHashCache(ht)) {
1224 key_hash = __CFBasicHashHashKey(ht, stack_key);
1226 stack_value = __CFBasicHashImportValue(ht, stack_value);
1227 if (ht->bits.keys_offset) {
1228 stack_key = __CFBasicHashImportKey(ht, stack_key);
1230 __CFBasicHashSetValue(ht, bkt_idx, stack_value, false, false);
1231 if (ht->bits.keys_offset) {
1232 __CFBasicHashSetKey(ht, bkt_idx, stack_key, false, false);
1234 if (ht->bits.counts_offset) {
1235 __CFBasicHashIncSlotCount(ht, bkt_idx);
1237 if (__CFBasicHashHasHashCache(ht)) {
1238 __CFBasicHashGetHashes(ht)[bkt_idx] = key_hash;
1240 ht->bits.used_buckets++;
1243 static void __CFBasicHashReplaceValue(CFBasicHashRef ht, CFIndex bkt_idx, uintptr_t stack_key, uintptr_t stack_value) {
1244 ht->bits.mutations++;
1245 stack_value = __CFBasicHashImportValue(ht, stack_value);
1246 if (ht->bits.keys_offset) {
1247 stack_key = __CFBasicHashImportKey(ht, stack_key);
1249 __CFBasicHashSetValue(ht, bkt_idx, stack_value, false, false);
1250 if (ht->bits.keys_offset) {
1251 __CFBasicHashSetKey(ht, bkt_idx, stack_key, false, false);
1255 static void __CFBasicHashRemoveValue(CFBasicHashRef ht, CFIndex bkt_idx) {
1256 ht->bits.mutations++;
1257 __CFBasicHashSetValue(ht, bkt_idx, ~0UL, false, true);
1258 if (ht->bits.keys_offset) {
1259 __CFBasicHashSetKey(ht, bkt_idx, ~0UL, false, true);
1261 if (ht->bits.counts_offset) {
1262 __CFBasicHashDecSlotCount(ht, bkt_idx);
1264 if (__CFBasicHashHasHashCache(ht)) {
1265 __CFBasicHashGetHashes(ht)[bkt_idx] = 0;
1267 ht->bits.used_buckets--;
1269 Boolean do_shrink = false;
1270 if (ht->bits.fast_grow) { // == slow shrink
1271 do_shrink = (5 < ht->bits.num_buckets_idx && ht->bits.used_buckets < __CFBasicHashGetCapacityForNumBuckets(ht, ht->bits.num_buckets_idx - 5));
1273 do_shrink = (2 < ht->bits.num_buckets_idx && ht->bits.used_buckets < __CFBasicHashGetCapacityForNumBuckets(ht, ht->bits.num_buckets_idx - 2));
1276 __CFBasicHashRehash(ht, -1);
1279 do_shrink = (0 == ht->bits.deleted); // .deleted roll-over
1280 CFIndex num_buckets = __CFBasicHashTableSizes[ht->bits.num_buckets_idx];
1281 do_shrink = do_shrink || ((20 <= num_buckets) && (num_buckets / 4 <= ht->bits.deleted));
1283 __CFBasicHashRehash(ht, 0);
1287 __private_extern__ Boolean CFBasicHashAddValue(CFBasicHashRef ht, uintptr_t stack_key, uintptr_t stack_value) {
1288 if (!CFBasicHashIsMutable(ht)) HALT;
1289 if (__CFBasicHashSubABZero == stack_key) HALT;
1290 if (__CFBasicHashSubABOne == stack_key) HALT;
1291 if (__CFBasicHashSubABZero == stack_value) HALT;
1292 if (__CFBasicHashSubABOne == stack_value) HALT;
1293 CFBasicHashBucket bkt = __CFBasicHashFindBucket(ht, stack_key);
1294 if (0 < bkt.count) {
1295 ht->bits.mutations++;
1296 if (ht->bits.counts_offset && bkt.count < LONG_MAX) { // if not yet as large as a CFIndex can be... otherwise clamp and do nothing
1297 __CFBasicHashIncSlotCount(ht, bkt.idx);
1301 __CFBasicHashAddValue(ht, bkt.idx, stack_key, stack_value);
1307 __private_extern__ void CFBasicHashReplaceValue(CFBasicHashRef ht, uintptr_t stack_key, uintptr_t stack_value) {
1308 if (!CFBasicHashIsMutable(ht)) HALT;
1309 if (__CFBasicHashSubABZero == stack_key) HALT;
1310 if (__CFBasicHashSubABOne == stack_key) HALT;
1311 if (__CFBasicHashSubABZero == stack_value) HALT;
1312 if (__CFBasicHashSubABOne == stack_value) HALT;
1313 CFBasicHashBucket bkt = __CFBasicHashFindBucket(ht, stack_key);
1314 if (0 < bkt.count) {
1315 __CFBasicHashReplaceValue(ht, bkt.idx, stack_key, stack_value);
1319 __private_extern__ void CFBasicHashSetValue(CFBasicHashRef ht, uintptr_t stack_key, uintptr_t stack_value) {
1320 if (!CFBasicHashIsMutable(ht)) HALT;
1321 if (__CFBasicHashSubABZero == stack_key) HALT;
1322 if (__CFBasicHashSubABOne == stack_key) HALT;
1323 if (__CFBasicHashSubABZero == stack_value) HALT;
1324 if (__CFBasicHashSubABOne == stack_value) HALT;
1325 CFBasicHashBucket bkt = __CFBasicHashFindBucket(ht, stack_key);
1326 if (0 < bkt.count) {
1327 __CFBasicHashReplaceValue(ht, bkt.idx, stack_key, stack_value);
1329 __CFBasicHashAddValue(ht, bkt.idx, stack_key, stack_value);
1333 __private_extern__ CFIndex CFBasicHashRemoveValue(CFBasicHashRef ht, uintptr_t stack_key) {
1334 if (!CFBasicHashIsMutable(ht)) HALT;
1335 if (__CFBasicHashSubABZero == stack_key || __CFBasicHashSubABOne == stack_key) return 0;
1336 CFBasicHashBucket bkt = __CFBasicHashFindBucket(ht, stack_key);
1337 if (1 < bkt.count) {
1338 ht->bits.mutations++;
1339 if (ht->bits.counts_offset && bkt.count < LONG_MAX) { // if not as large as a CFIndex can be... otherwise clamp and do nothing
1340 __CFBasicHashDecSlotCount(ht, bkt.idx);
1342 } else if (0 < bkt.count) {
1343 __CFBasicHashRemoveValue(ht, bkt.idx);
1348 __private_extern__ CFIndex CFBasicHashRemoveValueAtIndex(CFBasicHashRef ht, CFIndex idx) {
1349 if (!CFBasicHashIsMutable(ht)) HALT;
1350 CFBasicHashBucket bkt = CFBasicHashGetBucket(ht, idx);
1351 if (1 < bkt.count) {
1352 ht->bits.mutations++;
1353 if (ht->bits.counts_offset && bkt.count < LONG_MAX) { // if not as large as a CFIndex can be... otherwise clamp and do nothing
1354 __CFBasicHashDecSlotCount(ht, bkt.idx);
1356 } else if (0 < bkt.count) {
1357 __CFBasicHashRemoveValue(ht, bkt.idx);
1362 __private_extern__ void CFBasicHashRemoveAllValues(CFBasicHashRef ht) {
1363 if (!CFBasicHashIsMutable(ht)) HALT;
1364 if (0 == ht->bits.num_buckets_idx) return;
1365 __CFBasicHashDrain(ht, false);
1368 Boolean CFBasicHashAddIntValueAndInc(CFBasicHashRef ht, uintptr_t stack_key, uintptr_t int_value) {
1369 if (!CFBasicHashIsMutable(ht)) HALT;
1370 if (__CFBasicHashSubABZero == stack_key) HALT;
1371 if (__CFBasicHashSubABOne == stack_key) HALT;
1372 if (__CFBasicHashSubABZero == int_value) HALT;
1373 if (__CFBasicHashSubABOne == int_value) HALT;
1374 CFBasicHashBucket bkt = __CFBasicHashFindBucket(ht, stack_key);
1375 if (0 < bkt.count) {
1376 ht->bits.mutations++;
1378 // must rehash before renumbering
1379 if (CFBasicHashGetCapacity(ht) < ht->bits.used_buckets + 1) {
1380 __CFBasicHashRehash(ht, 1);
1381 bkt.idx = __CFBasicHashFindBucket_NoCollision(ht, stack_key, 0);
1383 CFIndex cnt = (CFIndex)__CFBasicHashTableSizes[ht->bits.num_buckets_idx];
1384 for (CFIndex idx = 0; idx < cnt; idx++) {
1385 if (!__CFBasicHashIsEmptyOrDeleted(ht, idx)) {
1386 uintptr_t stack_value = __CFBasicHashGetValue(ht, idx);
1387 if (int_value <= stack_value) {
1389 __CFBasicHashSetValue(ht, idx, stack_value, true, false);
1390 ht->bits.mutations++;
1394 __CFBasicHashAddValue(ht, bkt.idx, stack_key, int_value);
1400 void CFBasicHashRemoveIntValueAndDec(CFBasicHashRef ht, uintptr_t int_value) {
1401 if (!CFBasicHashIsMutable(ht)) HALT;
1402 if (__CFBasicHashSubABZero == int_value) HALT;
1403 if (__CFBasicHashSubABOne == int_value) HALT;
1404 uintptr_t bkt_idx = ~0UL;
1405 CFIndex cnt = (CFIndex)__CFBasicHashTableSizes[ht->bits.num_buckets_idx];
1406 for (CFIndex idx = 0; idx < cnt; idx++) {
1407 if (!__CFBasicHashIsEmptyOrDeleted(ht, idx)) {
1408 uintptr_t stack_value = __CFBasicHashGetValue(ht, idx);
1409 if (int_value == stack_value) {
1412 if (int_value < stack_value) {
1414 __CFBasicHashSetValue(ht, idx, stack_value, true, false);
1415 ht->bits.mutations++;
1419 __CFBasicHashRemoveValue(ht, bkt_idx);
1422 __private_extern__ size_t CFBasicHashGetSize(CFConstBasicHashRef ht, Boolean total) {
1423 size_t size = sizeof(struct __CFBasicHash);
1424 if (ht->bits.keys_offset) size += sizeof(CFBasicHashValue *);
1425 if (ht->bits.counts_offset) size += sizeof(void *);
1426 if (__CFBasicHashHasHashCache(ht)) size += sizeof(uintptr_t *);
1428 CFIndex num_buckets = __CFBasicHashTableSizes[ht->bits.num_buckets_idx];
1429 if (0 < num_buckets) {
1430 size += malloc_size(__CFBasicHashGetValues(ht));
1431 if (ht->bits.keys_offset) size += malloc_size(__CFBasicHashGetKeys(ht));
1432 if (ht->bits.counts_offset) size += malloc_size(__CFBasicHashGetCounts(ht));
1433 if (__CFBasicHashHasHashCache(ht)) size += malloc_size(__CFBasicHashGetHashes(ht));
1434 size += malloc_size((void *)ht->callbacks);
1440 __private_extern__ CFStringRef CFBasicHashCopyDescription(CFConstBasicHashRef ht, Boolean detailed, CFStringRef prefix, CFStringRef entryPrefix, Boolean describeElements) {
1441 CFMutableStringRef result = CFStringCreateMutable(kCFAllocatorSystemDefault, 0);
1442 CFStringAppendFormat(result, NULL, CFSTR("%@{type = %s %s%s, count = %ld,\n"), prefix, (CFBasicHashIsMutable(ht) ? "mutable" : "immutable"), ((ht->bits.counts_offset) ? "multi" : ""), ((ht->bits.keys_offset) ? "dict" : "set"), CFBasicHashGetCount(ht));
1444 const char *cb_type = "custom";
1445 CFStringAppendFormat(result, NULL, CFSTR("%@hash cache = %s, strong values = %s, strong keys = %s, cb = %s,\n"), prefix, (__CFBasicHashHasHashCache(ht) ? "yes" : "no"), (CFBasicHashHasStrongValues(ht) ? "yes" : "no"), (CFBasicHashHasStrongKeys(ht) ? "yes" : "no"), cb_type);
1446 CFStringAppendFormat(result, NULL, CFSTR("%@num bucket index = %d, num buckets = %ld, capacity = %d, num buckets used = %u,\n"), prefix, ht->bits.num_buckets_idx, CFBasicHashGetNumBuckets(ht), CFBasicHashGetCapacity(ht), ht->bits.used_buckets);
1447 CFStringAppendFormat(result, NULL, CFSTR("%@counts width = %d, finalized = %s,\n"), prefix,((ht->bits.counts_offset) ? (1 << ht->bits.counts_width) : 0), (ht->bits.finalized ? "yes" : "no"));
1448 CFStringAppendFormat(result, NULL, CFSTR("%@num mutations = %ld, num deleted = %ld, size = %ld, total size = %ld,\n"), prefix, ht->bits.mutations, ht->bits.deleted, CFBasicHashGetSize(ht, false), CFBasicHashGetSize(ht, true));
1449 CFStringAppendFormat(result, NULL, CFSTR("%@values ptr = %p, keys ptr = %p, counts ptr = %p, hashes ptr = %p,\n"), prefix, __CFBasicHashGetValues(ht), ((ht->bits.keys_offset) ? __CFBasicHashGetKeys(ht) : NULL), ((ht->bits.counts_offset) ? __CFBasicHashGetCounts(ht) : NULL), (__CFBasicHashHasHashCache(ht) ? __CFBasicHashGetHashes(ht) : NULL));
1451 CFStringAppendFormat(result, NULL, CFSTR("%@entries =>\n"), prefix);
1452 CFBasicHashApply(ht, ^(CFBasicHashBucket bkt) {
1453 CFStringRef vDesc = NULL, kDesc = NULL;
1454 if (!describeElements) {
1455 vDesc = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<%p>"), (void *)bkt.weak_value);
1456 if (ht->bits.keys_offset) {
1457 kDesc = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<%p>"), (void *)bkt.weak_key);
1460 vDesc = ht->callbacks->copyValueDescription(ht, bkt.weak_value);
1461 if (ht->bits.keys_offset) {
1462 kDesc = ht->callbacks->copyKeyDescription(ht, bkt.weak_key);
1465 if (ht->bits.keys_offset && ht->bits.counts_offset) {
1466 CFStringAppendFormat(result, NULL, CFSTR("%@%ld : %@ = %@ (%ld)\n"), entryPrefix, bkt.idx, kDesc, vDesc, bkt.count);
1467 } else if (ht->bits.keys_offset) {
1468 CFStringAppendFormat(result, NULL, CFSTR("%@%ld : %@ = %@\n"), entryPrefix, bkt.idx, kDesc, vDesc);
1469 } else if (ht->bits.counts_offset) {
1470 CFStringAppendFormat(result, NULL, CFSTR("%@%ld : %@ (%ld)\n"), entryPrefix, bkt.idx, vDesc, bkt.count);
1472 CFStringAppendFormat(result, NULL, CFSTR("%@%ld : %@\n"), entryPrefix, bkt.idx, vDesc);
1474 if (kDesc) CFRelease(kDesc);
1475 if (vDesc) CFRelease(vDesc);
1476 return (Boolean)true;
1478 CFStringAppendFormat(result, NULL, CFSTR("%@}\n"), prefix);
1482 __private_extern__ void CFBasicHashShow(CFConstBasicHashRef ht) {
1483 CFStringRef str = CFBasicHashCopyDescription(ht, true, CFSTR(""), CFSTR("\t"), false);
1488 __private_extern__ Boolean __CFBasicHashEqual(CFTypeRef cf1, CFTypeRef cf2) {
1489 CFBasicHashRef ht1 = (CFBasicHashRef)cf1;
1490 CFBasicHashRef ht2 = (CFBasicHashRef)cf2;
1491 //#warning this used to require that the key and value equal callbacks were pointer identical
1492 return CFBasicHashesAreEqual(ht1, ht2);
1495 __private_extern__ CFHashCode __CFBasicHashHash(CFTypeRef cf) {
1496 CFBasicHashRef ht = (CFBasicHashRef)cf;
1497 return CFBasicHashGetCount(ht);
1500 __private_extern__ CFStringRef __CFBasicHashCopyDescription(CFTypeRef cf) {
1501 CFBasicHashRef ht = (CFBasicHashRef)cf;
1502 CFStringRef desc = CFBasicHashCopyDescription(ht, false, CFSTR(""), CFSTR("\t"), true);
1503 CFStringRef result = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<CFBasicHash %p [%p]>%@"), cf, CFGetAllocator(cf), desc);
1508 __private_extern__ void __CFBasicHashDeallocate(CFTypeRef cf) {
1509 CFBasicHashRef ht = (CFBasicHashRef)cf;
1510 if (ht->bits.finalized) HALT;
1511 ht->bits.finalized = 1;
1512 __CFBasicHashDrain(ht, true);
1513 #if ENABLE_MEMORY_COUNTERS
1514 OSAtomicAdd64Barrier(-1, &__CFBasicHashTotalCount);
1515 OSAtomicAdd32Barrier(-1, &__CFBasicHashSizes[ht->bits.num_buckets_idx]);
1519 static CFTypeID __kCFBasicHashTypeID = _kCFRuntimeNotATypeID;
1521 static const CFRuntimeClass __CFBasicHashClass = {
1522 _kCFRuntimeScannedObject,
1526 __CFBasicHashDeallocate,
1530 __CFBasicHashCopyDescription
1533 __private_extern__ CFTypeID CFBasicHashGetTypeID(void) {
1534 if (_kCFRuntimeNotATypeID == __kCFBasicHashTypeID) __kCFBasicHashTypeID = _CFRuntimeRegisterClass(&__CFBasicHashClass);
1535 return __kCFBasicHashTypeID;
1538 CFBasicHashRef CFBasicHashCreate(CFAllocatorRef allocator, CFOptionFlags flags, const CFBasicHashCallbacks *cb) {
1539 size_t size = sizeof(struct __CFBasicHash) - sizeof(CFRuntimeBase);
1540 if (flags & kCFBasicHashHasKeys) size += sizeof(CFBasicHashValue *); // keys
1541 if (flags & kCFBasicHashHasCounts) size += sizeof(void *); // counts
1542 if (flags & kCFBasicHashHasHashCache) size += sizeof(uintptr_t *); // hashes
1543 CFBasicHashRef ht = (CFBasicHashRef)_CFRuntimeCreateInstance(allocator, CFBasicHashGetTypeID(), size, NULL);
1544 if (NULL == ht) HALT;
1546 ht->bits.finalized = 0;
1547 ht->bits.hash_style = (flags >> 13) & 0x3;
1548 ht->bits.fast_grow = (flags & kCFBasicHashAggressiveGrowth) ? 1 : 0;
1549 ht->bits.counts_width = 0;
1550 ht->bits.strong_values = (flags & kCFBasicHashStrongValues) ? 1 : 0;
1551 ht->bits.strong_keys = (flags & kCFBasicHashStrongKeys) ? 1 : 0;
1552 ht->bits.weak_values = (flags & kCFBasicHashWeakValues) ? 1 : 0;
1553 ht->bits.weak_keys = (flags & kCFBasicHashWeakKeys) ? 1 : 0;
1554 ht->bits.int_values = (flags & kCFBasicHashIntegerValues) ? 1 : 0;
1555 ht->bits.int_keys = (flags & kCFBasicHashIntegerKeys) ? 1 : 0;
1556 ht->bits.indirect_keys = (flags & kCFBasicHashIndirectKeys) ? 1 : 0;
1557 ht->bits.compactable_keys = (flags & kCFBasicHashCompactableKeys) ? 1 : 0;
1558 ht->bits.compactable_values = (flags & kCFBasicHashCompactableValues) ? 1 : 0;
1562 ht->bits.num_buckets_idx = 0;
1563 ht->bits.used_buckets = 0;
1564 ht->bits.deleted = 0;
1565 ht->bits.mutations = 1;
1567 if (ht->bits.strong_values && ht->bits.weak_values) HALT;
1568 if (ht->bits.strong_values && ht->bits.int_values) HALT;
1569 if (ht->bits.strong_keys && ht->bits.weak_keys) HALT;
1570 if (ht->bits.strong_keys && ht->bits.int_keys) HALT;
1571 if (ht->bits.weak_values && ht->bits.int_values) HALT;
1572 if (ht->bits.weak_keys && ht->bits.int_keys) HALT;
1573 if (ht->bits.indirect_keys && ht->bits.strong_keys) HALT;
1574 if (ht->bits.indirect_keys && ht->bits.weak_keys) HALT;
1575 if (ht->bits.indirect_keys && ht->bits.int_keys) HALT;
1577 uint64_t offset = 1;
1578 ht->bits.keys_offset = (flags & kCFBasicHashHasKeys) ? offset++ : 0;
1579 ht->bits.counts_offset = (flags & kCFBasicHashHasCounts) ? offset++ : 0;
1580 ht->bits.hashes_offset = (flags & kCFBasicHashHasHashCache) ? offset++ : 0;
1582 #if defined(__arm__)
1583 ht->bits.hashes_offset = 0;
1584 ht->bits.strong_values = 0;
1585 ht->bits.strong_keys = 0;
1586 ht->bits.weak_values = 0;
1587 ht->bits.weak_keys = 0;
1590 __AssignWithWriteBarrier(&ht->callbacks, cb);
1591 for (CFIndex idx = 0; idx < offset; idx++) {
1592 ht->pointers[idx] = NULL;
1595 #if ENABLE_MEMORY_COUNTERS
1596 int64_t size_now = OSAtomicAdd64Barrier((int64_t) CFBasicHashGetSize(ht, true), & __CFBasicHashTotalSize);
1597 while (__CFBasicHashPeakSize < size_now && !OSAtomicCompareAndSwap64Barrier(__CFBasicHashPeakSize, size_now, & __CFBasicHashPeakSize));
1598 int64_t count_now = OSAtomicAdd64Barrier(1, & __CFBasicHashTotalCount);
1599 while (__CFBasicHashPeakCount < count_now && !OSAtomicCompareAndSwap64Barrier(__CFBasicHashPeakCount, count_now, & __CFBasicHashPeakCount));
1600 OSAtomicAdd32Barrier(1, &__CFBasicHashSizes[ht->bits.num_buckets_idx]);
1606 CFBasicHashRef CFBasicHashCreateCopy(CFAllocatorRef allocator, CFConstBasicHashRef src_ht) {
1607 size_t size = CFBasicHashGetSize(src_ht, false) - sizeof(CFRuntimeBase);
1608 CFBasicHashRef ht = (CFBasicHashRef)_CFRuntimeCreateInstance(allocator, CFBasicHashGetTypeID(), size, NULL);
1609 if (NULL == ht) HALT;
1611 memmove((uint8_t *)ht + sizeof(CFRuntimeBase), (uint8_t *)src_ht + sizeof(CFRuntimeBase), sizeof(ht->bits));
1612 if (kCFUseCollectableAllocator && !CF_IS_COLLECTABLE_ALLOCATOR(allocator)) {
1613 ht->bits.strong_values = 0;
1614 ht->bits.strong_keys = 0;
1615 ht->bits.weak_values = 0;
1616 ht->bits.weak_keys = 0;
1618 ht->bits.finalized = 0;
1619 ht->bits.mutations = 1;
1620 CFBasicHashCallbacks *newcb = src_ht->callbacks->copyCallbacks(src_ht, allocator, src_ht->callbacks);
1621 if (NULL == newcb) HALT;
1622 __AssignWithWriteBarrier(&ht->callbacks, newcb);
1624 CFIndex new_num_buckets = __CFBasicHashTableSizes[ht->bits.num_buckets_idx];
1625 if (0 == new_num_buckets) {
1626 #if ENABLE_MEMORY_COUNTERS
1627 int64_t size_now = OSAtomicAdd64Barrier((int64_t) CFBasicHashGetSize(ht, true), & __CFBasicHashTotalSize);
1628 while (__CFBasicHashPeakSize < size_now && !OSAtomicCompareAndSwap64Barrier(__CFBasicHashPeakSize, size_now, & __CFBasicHashPeakSize));
1629 int64_t count_now = OSAtomicAdd64Barrier(1, & __CFBasicHashTotalCount);
1630 while (__CFBasicHashPeakCount < count_now && !OSAtomicCompareAndSwap64Barrier(__CFBasicHashPeakCount, count_now, & __CFBasicHashPeakCount));
1631 OSAtomicAdd32Barrier(1, &__CFBasicHashSizes[ht->bits.num_buckets_idx]);
1636 CFBasicHashValue *new_values = NULL, *new_keys = NULL;
1637 void *new_counts = NULL;
1638 uintptr_t *new_hashes = NULL;
1640 if (0 < new_num_buckets) {
1641 new_values = (CFBasicHashValue *)__CFBasicHashAllocateMemory(ht, new_num_buckets, sizeof(CFBasicHashValue), CFBasicHashHasStrongValues(ht), __CFBasicHashHasCompactableValues(ht));
1642 __SetLastAllocationEventName(new_values, "CFBasicHash (value-store)");
1643 if (ht->bits.keys_offset) {
1644 new_keys = (CFBasicHashValue *)__CFBasicHashAllocateMemory(ht, new_num_buckets, sizeof(CFBasicHashValue), CFBasicHashHasStrongKeys(ht), false);
1645 __SetLastAllocationEventName(new_keys, "CFBasicHash (key-store)");
1647 if (ht->bits.counts_offset) {
1648 new_counts = (uintptr_t *)__CFBasicHashAllocateMemory(ht, new_num_buckets, (1 << ht->bits.counts_width), false, false);
1649 __SetLastAllocationEventName(new_counts, "CFBasicHash (count-store)");
1651 if (__CFBasicHashHasHashCache(ht)) {
1652 new_hashes = (uintptr_t *)__CFBasicHashAllocateMemory(ht, new_num_buckets, sizeof(uintptr_t), false, false);
1653 __SetLastAllocationEventName(new_hashes, "CFBasicHash (hash-store)");
1657 CFBasicHashValue *old_values = NULL, *old_keys = NULL;
1658 void *old_counts = NULL;
1659 uintptr_t *old_hashes = NULL;
1661 old_values = __CFBasicHashGetValues(src_ht);
1662 if (src_ht->bits.keys_offset) {
1663 old_keys = __CFBasicHashGetKeys(src_ht);
1665 if (src_ht->bits.counts_offset) {
1666 old_counts = __CFBasicHashGetCounts(src_ht);
1668 if (__CFBasicHashHasHashCache(src_ht)) {
1669 old_hashes = __CFBasicHashGetHashes(src_ht);
1672 __CFBasicHashSetValues(ht, new_values);
1674 __CFBasicHashSetKeys(ht, new_keys);
1677 __CFBasicHashSetCounts(ht, new_counts);
1680 __CFBasicHashSetHashes(ht, new_hashes);
1683 for (CFIndex idx = 0; idx < new_num_buckets; idx++) {
1684 uintptr_t stack_value = old_values[idx].neutral;
1685 if (stack_value != 0UL && stack_value != ~0UL) {
1686 uintptr_t old_value = stack_value;
1687 if (__CFBasicHashSubABZero == old_value) old_value = 0UL;
1688 if (__CFBasicHashSubABOne == old_value) old_value = ~0UL;
1689 __CFBasicHashSetValue(ht, idx, __CFBasicHashImportValue(ht, old_value), true, false);
1691 uintptr_t old_key = old_keys[idx].neutral;
1692 if (__CFBasicHashSubABZero == old_key) old_key = 0UL;
1693 if (__CFBasicHashSubABOne == old_key) old_key = ~0UL;
1694 __CFBasicHashSetKey(ht, idx, __CFBasicHashImportKey(ht, old_key), true, false);
1697 __CFBasicHashSetValue(ht, idx, stack_value, true, true);
1699 __CFBasicHashSetKey(ht, idx, stack_value, true, true);
1703 if (new_counts) memmove(new_counts, old_counts, new_num_buckets * (1 << ht->bits.counts_width));
1704 if (new_hashes) memmove(new_hashes, old_hashes, new_num_buckets * sizeof(uintptr_t));
1706 #if ENABLE_MEMORY_COUNTERS
1707 int64_t size_now = OSAtomicAdd64Barrier((int64_t) CFBasicHashGetSize(ht, true), & __CFBasicHashTotalSize);
1708 while (__CFBasicHashPeakSize < size_now && !OSAtomicCompareAndSwap64Barrier(__CFBasicHashPeakSize, size_now, & __CFBasicHashPeakSize));
1709 int64_t count_now = OSAtomicAdd64Barrier(1, & __CFBasicHashTotalCount);
1710 while (__CFBasicHashPeakCount < count_now && !OSAtomicCompareAndSwap64Barrier(__CFBasicHashPeakCount, count_now, & __CFBasicHashPeakCount));
1711 OSAtomicAdd32Barrier(1, &__CFBasicHashSizes[ht->bits.num_buckets_idx]);
1717 __private_extern__ void __CFBasicHashSetCallbacks(CFBasicHashRef ht, const CFBasicHashCallbacks *cb) {
1718 __AssignWithWriteBarrier(&ht->callbacks, cb);
1721 void _CFbhx588461(CFBasicHashRef ht, Boolean growth) {
1722 if (!CFBasicHashIsMutable(ht)) HALT;
1723 if (ht->bits.finalized) HALT;
1724 ht->bits.fast_grow = growth ? 1 : 0;