2 * Copyright (c) 2014 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-2013, Apple Inc. All rights reserved.
26 Responsibility: Christopher Kane
29 #import "CFBasicHash.h"
30 #import <CoreFoundation/CFRuntime.h>
31 #import <CoreFoundation/CFSet.h>
34 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
35 #import <dispatch/dispatch.h>
38 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
39 #define __SetLastAllocationEventName(A, B) do { if (__CFOASafe && (A)) __CFSetLastAllocationEventName(A, B); } while (0)
41 #define __SetLastAllocationEventName(A, B) do { } while (0)
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);
289 CF_INLINE
void *__CFBasicHashAllocateMemory2(CFAllocatorRef allocator
, CFIndex count
, CFIndex elem_size
, Boolean strong
, Boolean compactable
) {
290 void *new_mem
= NULL
;
291 if (CF_IS_COLLECTABLE_ALLOCATOR(allocator
)) {
292 new_mem
= auto_zone_allocate_object(objc_collectableZone(), count
* elem_size
, strong
? (compactable
? AUTO_POINTERS_ONLY
: AUTO_MEMORY_SCANNED
) : AUTO_UNSCANNED
, false, false);
294 new_mem
= CFAllocatorAllocate(allocator
, count
* elem_size
, 0);
299 #define __CFBasicHashSubABZero 0xa7baadb1
300 #define __CFBasicHashSubABOne 0xa5baadb9
308 struct __CFBasicHash
{
312 uint8_t hash_style
:2;
313 uint8_t keys_offset
:1;
314 uint8_t counts_offset
:2;
315 uint8_t counts_width
:2;
316 uint8_t hashes_offset
:2;
317 uint8_t strong_values
:1;
318 uint8_t strong_keys
:1;
319 uint8_t weak_values
:1;
321 uint8_t int_values
:1;
323 uint8_t indirect_keys
:1;
324 uint32_t used_buckets
; /* number of used buckets */
326 uint64_t num_buckets_idx
:8; /* index to number of buckets */
333 uint64_t fast_grow
:1;
334 uint64_t finalized
:1;
345 static void *CFBasicHashCallBackPtrs
[(1UL << 10)];
346 static int32_t CFBasicHashCallBackPtrsCount
= 0;
348 static int32_t CFBasicHashGetPtrIndex(void *ptr
) {
349 static dispatch_once_t once
;
350 dispatch_once(&once
, ^{
351 CFBasicHashCallBackPtrs
[0] = NULL
;
352 CFBasicHashCallBackPtrs
[1] = (void *)CFCopyDescription
;
353 CFBasicHashCallBackPtrs
[2] = (void *)__CFTypeCollectionRelease
;
354 CFBasicHashCallBackPtrs
[3] = (void *)__CFTypeCollectionRetain
;
355 CFBasicHashCallBackPtrs
[4] = (void *)CFEqual
;
356 CFBasicHashCallBackPtrs
[5] = (void *)CFHash
;
357 CFBasicHashCallBackPtrs
[6] = (void *)__CFStringCollectionCopy
;
358 CFBasicHashCallBackPtrs
[7] = NULL
;
359 CFBasicHashCallBackPtrsCount
= 8;
362 // The uniquing here is done locklessly for best performance, and in
363 // a way that will keep multiple threads from stomping each other's
364 // newly registered values, but may result in multiple slots
365 // containing the same pointer value.
368 for (idx
= 0; idx
< CFBasicHashCallBackPtrsCount
; idx
++) {
369 if (CFBasicHashCallBackPtrs
[idx
] == ptr
) return idx
;
372 if (1000 < CFBasicHashCallBackPtrsCount
) HALT
;
373 idx
= OSAtomicIncrement32(&CFBasicHashCallBackPtrsCount
); // returns new value
374 CFBasicHashCallBackPtrs
[idx
- 1] = ptr
;
378 CF_PRIVATE Boolean
CFBasicHashHasStrongValues(CFConstBasicHashRef ht
) {
379 #if DEPLOYMENT_TARGET_MACOSX
380 return ht
->bits
.strong_values
? true : false;
386 CF_PRIVATE Boolean
CFBasicHashHasStrongKeys(CFConstBasicHashRef ht
) {
387 #if DEPLOYMENT_TARGET_MACOSX
388 return ht
->bits
.strong_keys
? true : false;
394 CF_INLINE Boolean
__CFBasicHashHasWeakValues(CFConstBasicHashRef ht
) {
395 #if DEPLOYMENT_TARGET_MACOSX
396 return ht
->bits
.weak_values
? true : false;
402 CF_INLINE Boolean
__CFBasicHashHasWeakKeys(CFConstBasicHashRef ht
) {
403 #if DEPLOYMENT_TARGET_MACOSX
404 return ht
->bits
.weak_keys
? true : false;
410 CF_INLINE Boolean
__CFBasicHashHasHashCache(CFConstBasicHashRef ht
) {
411 #if DEPLOYMENT_TARGET_MACOSX
412 return ht
->bits
.hashes_offset
? true : false;
418 CF_INLINE
uintptr_t __CFBasicHashImportValue(CFConstBasicHashRef ht
, uintptr_t stack_value
) {
419 uintptr_t (*func
)(CFAllocatorRef
, uintptr_t) = (uintptr_t (*)(CFAllocatorRef
, uintptr_t))CFBasicHashCallBackPtrs
[ht
->bits
.__vret
];
420 if (!func
|| ht
->bits
.null_rc
) return stack_value
;
421 CFAllocatorRef alloc
= CFGetAllocator(ht
);
422 return func(alloc
, stack_value
);
425 CF_INLINE
uintptr_t __CFBasicHashImportKey(CFConstBasicHashRef ht
, uintptr_t stack_key
) {
426 uintptr_t (*func
)(CFAllocatorRef
, uintptr_t) = (uintptr_t (*)(CFAllocatorRef
, uintptr_t))CFBasicHashCallBackPtrs
[ht
->bits
.__kret
];
427 if (!func
|| ht
->bits
.null_rc
) return stack_key
;
428 CFAllocatorRef alloc
= CFGetAllocator(ht
);
429 return func(alloc
, stack_key
);
432 CF_INLINE
void __CFBasicHashEjectValue(CFConstBasicHashRef ht
, uintptr_t stack_value
) {
433 void (*func
)(CFAllocatorRef
, uintptr_t) = (void (*)(CFAllocatorRef
, uintptr_t))CFBasicHashCallBackPtrs
[ht
->bits
.__vrel
];
434 if (!func
|| ht
->bits
.null_rc
) return;
435 CFAllocatorRef alloc
= CFGetAllocator(ht
);
436 func(alloc
, stack_value
);
439 CF_INLINE
void __CFBasicHashEjectKey(CFConstBasicHashRef ht
, uintptr_t stack_key
) {
440 void (*func
)(CFAllocatorRef
, uintptr_t) = (void (*)(CFAllocatorRef
, uintptr_t))CFBasicHashCallBackPtrs
[ht
->bits
.__krel
];
441 if (!func
|| ht
->bits
.null_rc
) return;
442 CFAllocatorRef alloc
= CFGetAllocator(ht
);
443 func(alloc
, stack_key
);
446 CF_INLINE CFStringRef
__CFBasicHashDescValue(CFConstBasicHashRef ht
, uintptr_t stack_value
) {
447 CFStringRef (*func
)(uintptr_t) = (CFStringRef (*)(uintptr_t))CFBasicHashCallBackPtrs
[ht
->bits
.__vdes
];
448 if (!func
) return CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("<%p>"), (void *)stack_value
);
449 return func(stack_value
);
452 CF_INLINE CFStringRef
__CFBasicHashDescKey(CFConstBasicHashRef ht
, uintptr_t stack_key
) {
453 CFStringRef (*func
)(uintptr_t) = (CFStringRef (*)(uintptr_t))CFBasicHashCallBackPtrs
[ht
->bits
.__kdes
];
454 if (!func
) return CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("<%p>"), (void *)stack_key
);
455 return func(stack_key
);
458 CF_INLINE Boolean
__CFBasicHashTestEqualValue(CFConstBasicHashRef ht
, uintptr_t stack_value_a
, uintptr_t stack_value_b
) {
459 Boolean (*func
)(uintptr_t, uintptr_t) = (Boolean (*)(uintptr_t, uintptr_t))CFBasicHashCallBackPtrs
[ht
->bits
.__vequ
];
460 if (!func
) return (stack_value_a
== stack_value_b
);
461 return func(stack_value_a
, stack_value_b
);
464 CF_INLINE Boolean
__CFBasicHashTestEqualKey(CFConstBasicHashRef ht
, uintptr_t in_coll_key
, uintptr_t stack_key
) {
465 COCOA_HASHTABLE_TEST_EQUAL(ht
, in_coll_key
, stack_key
);
466 Boolean (*func
)(uintptr_t, uintptr_t) = (Boolean (*)(uintptr_t, uintptr_t))CFBasicHashCallBackPtrs
[ht
->bits
.__kequ
];
467 if (!func
) return (in_coll_key
== stack_key
);
468 return func(in_coll_key
, stack_key
);
471 CF_INLINE CFHashCode
__CFBasicHashHashKey(CFConstBasicHashRef ht
, uintptr_t stack_key
) {
472 CFHashCode (*func
)(uintptr_t) = (CFHashCode (*)(uintptr_t))CFBasicHashCallBackPtrs
[ht
->bits
.__khas
];
473 CFHashCode hash_code
= func
? func(stack_key
) : stack_key
;
474 COCOA_HASHTABLE_HASH_KEY(ht
, stack_key
, hash_code
);
478 CF_INLINE
uintptr_t __CFBasicHashGetIndirectKey(CFConstBasicHashRef ht
, uintptr_t coll_key
) {
479 uintptr_t (*func
)(uintptr_t) = (uintptr_t (*)(uintptr_t))CFBasicHashCallBackPtrs
[ht
->bits
.__kget
];
480 if (!func
) return coll_key
;
481 return func(coll_key
);
484 CF_INLINE CFBasicHashValue
*__CFBasicHashGetValues(CFConstBasicHashRef ht
) {
485 return (CFBasicHashValue
*)ht
->pointers
[0];
488 CF_INLINE
void __CFBasicHashSetValues(CFBasicHashRef ht
, CFBasicHashValue
*ptr
) {
489 __AssignWithWriteBarrier(&ht
->pointers
[0], ptr
);
492 CF_INLINE CFBasicHashValue
*__CFBasicHashGetKeys(CFConstBasicHashRef ht
) {
493 return (CFBasicHashValue
*)ht
->pointers
[ht
->bits
.keys_offset
];
496 CF_INLINE
void __CFBasicHashSetKeys(CFBasicHashRef ht
, CFBasicHashValue
*ptr
) {
497 __AssignWithWriteBarrier(&ht
->pointers
[ht
->bits
.keys_offset
], ptr
);
500 CF_INLINE
void *__CFBasicHashGetCounts(CFConstBasicHashRef ht
) {
501 return (void *)ht
->pointers
[ht
->bits
.counts_offset
];
504 CF_INLINE
void __CFBasicHashSetCounts(CFBasicHashRef ht
, void *ptr
) {
505 __AssignWithWriteBarrier(&ht
->pointers
[ht
->bits
.counts_offset
], ptr
);
508 CF_INLINE
uintptr_t __CFBasicHashGetValue(CFConstBasicHashRef ht
, CFIndex idx
) {
509 uintptr_t val
= __CFBasicHashGetValues(ht
)[idx
].neutral
;
510 if (__CFBasicHashSubABZero
== val
) return 0UL;
511 if (__CFBasicHashSubABOne
== val
) return ~0UL;
515 CF_INLINE
void __CFBasicHashSetValue(CFBasicHashRef ht
, CFIndex idx
, uintptr_t stack_value
, Boolean ignoreOld
, Boolean literal
) {
516 CFBasicHashValue
*valuep
= &(__CFBasicHashGetValues(ht
)[idx
]);
517 uintptr_t old_value
= ignoreOld
? 0 : valuep
->neutral
;
519 if (0UL == stack_value
) stack_value
= __CFBasicHashSubABZero
;
520 if (~0UL == stack_value
) stack_value
= __CFBasicHashSubABOne
;
522 if (CFBasicHashHasStrongValues(ht
)) valuep
->strong
= (id
)stack_value
; else valuep
->neutral
= stack_value
;
524 if (!(old_value
== 0UL || old_value
== ~0UL)) {
525 if (__CFBasicHashSubABZero
== old_value
) old_value
= 0UL;
526 if (__CFBasicHashSubABOne
== old_value
) old_value
= ~0UL;
527 __CFBasicHashEjectValue(ht
, old_value
);
532 CF_INLINE
uintptr_t __CFBasicHashGetKey(CFConstBasicHashRef ht
, CFIndex idx
) {
533 if (ht
->bits
.keys_offset
) {
534 uintptr_t key
= __CFBasicHashGetKeys(ht
)[idx
].neutral
;
535 if (__CFBasicHashSubABZero
== key
) return 0UL;
536 if (__CFBasicHashSubABOne
== key
) return ~0UL;
539 if (ht
->bits
.indirect_keys
) {
540 uintptr_t stack_value
= __CFBasicHashGetValue(ht
, idx
);
541 return __CFBasicHashGetIndirectKey(ht
, stack_value
);
543 return __CFBasicHashGetValue(ht
, idx
);
546 CF_INLINE
void __CFBasicHashSetKey(CFBasicHashRef ht
, CFIndex idx
, uintptr_t stack_key
, Boolean ignoreOld
, Boolean literal
) {
547 if (0 == ht
->bits
.keys_offset
) HALT
;
548 CFBasicHashValue
*keyp
= &(__CFBasicHashGetKeys(ht
)[idx
]);
549 uintptr_t old_key
= ignoreOld
? 0 : keyp
->neutral
;
551 if (0UL == stack_key
) stack_key
= __CFBasicHashSubABZero
;
552 if (~0UL == stack_key
) stack_key
= __CFBasicHashSubABOne
;
554 if (CFBasicHashHasStrongKeys(ht
)) keyp
->strong
= (id
)stack_key
; else keyp
->neutral
= stack_key
;
556 if (!(old_key
== 0UL || old_key
== ~0UL)) {
557 if (__CFBasicHashSubABZero
== old_key
) old_key
= 0UL;
558 if (__CFBasicHashSubABOne
== old_key
) old_key
= ~0UL;
559 __CFBasicHashEjectKey(ht
, old_key
);
564 CF_INLINE
uintptr_t __CFBasicHashIsEmptyOrDeleted(CFConstBasicHashRef ht
, CFIndex idx
) {
565 uintptr_t stack_value
= __CFBasicHashGetValues(ht
)[idx
].neutral
;
566 return (0UL == stack_value
|| ~0UL == stack_value
);
569 CF_INLINE
uintptr_t __CFBasicHashIsDeleted(CFConstBasicHashRef ht
, CFIndex idx
) {
570 uintptr_t stack_value
= __CFBasicHashGetValues(ht
)[idx
].neutral
;
571 return (~0UL == stack_value
);
574 CF_INLINE
uintptr_t __CFBasicHashGetSlotCount(CFConstBasicHashRef ht
, CFIndex idx
) {
575 void *counts
= __CFBasicHashGetCounts(ht
);
576 switch (ht
->bits
.counts_width
) {
577 case 0: return ((uint8_t *)counts
)[idx
];
578 case 1: return ((uint16_t *)counts
)[idx
];
579 case 2: return ((uint32_t *)counts
)[idx
];
580 case 3: return ((uint64_t *)counts
)[idx
];
585 CF_INLINE
void __CFBasicHashBumpCounts(CFBasicHashRef ht
) {
586 void *counts
= __CFBasicHashGetCounts(ht
);
587 CFAllocatorRef allocator
= CFGetAllocator(ht
);
588 switch (ht
->bits
.counts_width
) {
590 uint8_t *counts08
= (uint8_t *)counts
;
591 ht
->bits
.counts_width
= 1;
592 CFIndex num_buckets
= __CFBasicHashTableSizes
[ht
->bits
.num_buckets_idx
];
593 uint16_t *counts16
= (uint16_t *)__CFBasicHashAllocateMemory(ht
, num_buckets
, 2, false, false);
595 __SetLastAllocationEventName(counts16
, "CFBasicHash (count-store)");
596 for (CFIndex idx2
= 0; idx2
< num_buckets
; idx2
++) {
597 counts16
[idx2
] = counts08
[idx2
];
599 __CFBasicHashSetCounts(ht
, counts16
);
600 if (!CF_IS_COLLECTABLE_ALLOCATOR(allocator
)) {
601 CFAllocatorDeallocate(allocator
, counts08
);
606 uint16_t *counts16
= (uint16_t *)counts
;
607 ht
->bits
.counts_width
= 2;
608 CFIndex num_buckets
= __CFBasicHashTableSizes
[ht
->bits
.num_buckets_idx
];
609 uint32_t *counts32
= (uint32_t *)__CFBasicHashAllocateMemory(ht
, num_buckets
, 4, false, false);
611 __SetLastAllocationEventName(counts32
, "CFBasicHash (count-store)");
612 for (CFIndex idx2
= 0; idx2
< num_buckets
; idx2
++) {
613 counts32
[idx2
] = counts16
[idx2
];
615 __CFBasicHashSetCounts(ht
, counts32
);
616 if (!CF_IS_COLLECTABLE_ALLOCATOR(allocator
)) {
617 CFAllocatorDeallocate(allocator
, counts16
);
622 uint32_t *counts32
= (uint32_t *)counts
;
623 ht
->bits
.counts_width
= 3;
624 CFIndex num_buckets
= __CFBasicHashTableSizes
[ht
->bits
.num_buckets_idx
];
625 uint64_t *counts64
= (uint64_t *)__CFBasicHashAllocateMemory(ht
, num_buckets
, 8, false, false);
627 __SetLastAllocationEventName(counts64
, "CFBasicHash (count-store)");
628 for (CFIndex idx2
= 0; idx2
< num_buckets
; idx2
++) {
629 counts64
[idx2
] = counts32
[idx2
];
631 __CFBasicHashSetCounts(ht
, counts64
);
632 if (!CF_IS_COLLECTABLE_ALLOCATOR(allocator
)) {
633 CFAllocatorDeallocate(allocator
, counts32
);
644 static void __CFBasicHashIncSlotCount(CFBasicHashRef ht
, CFIndex idx
) {
645 void *counts
= __CFBasicHashGetCounts(ht
);
646 switch (ht
->bits
.counts_width
) {
648 uint8_t *counts08
= (uint8_t *)counts
;
649 uint8_t val
= counts08
[idx
];
650 if (val
< INT8_MAX
) {
651 counts08
[idx
] = val
+ 1;
654 __CFBasicHashBumpCounts(ht
);
655 __CFBasicHashIncSlotCount(ht
, idx
);
659 uint16_t *counts16
= (uint16_t *)counts
;
660 uint16_t val
= counts16
[idx
];
661 if (val
< INT16_MAX
) {
662 counts16
[idx
] = val
+ 1;
665 __CFBasicHashBumpCounts(ht
);
666 __CFBasicHashIncSlotCount(ht
, idx
);
670 uint32_t *counts32
= (uint32_t *)counts
;
671 uint32_t val
= counts32
[idx
];
672 if (val
< INT32_MAX
) {
673 counts32
[idx
] = val
+ 1;
676 __CFBasicHashBumpCounts(ht
);
677 __CFBasicHashIncSlotCount(ht
, idx
);
681 uint64_t *counts64
= (uint64_t *)counts
;
682 uint64_t val
= counts64
[idx
];
683 if (val
< INT64_MAX
) {
684 counts64
[idx
] = val
+ 1;
687 __CFBasicHashBumpCounts(ht
);
688 __CFBasicHashIncSlotCount(ht
, idx
);
694 CF_INLINE
void __CFBasicHashDecSlotCount(CFBasicHashRef ht
, CFIndex idx
) {
695 void *counts
= __CFBasicHashGetCounts(ht
);
696 switch (ht
->bits
.counts_width
) {
697 case 0: ((uint8_t *)counts
)[idx
]--; return;
698 case 1: ((uint16_t *)counts
)[idx
]--; return;
699 case 2: ((uint32_t *)counts
)[idx
]--; return;
700 case 3: ((uint64_t *)counts
)[idx
]--; return;
704 CF_INLINE
uintptr_t *__CFBasicHashGetHashes(CFConstBasicHashRef ht
) {
705 return (uintptr_t *)ht
->pointers
[ht
->bits
.hashes_offset
];
708 CF_INLINE
void __CFBasicHashSetHashes(CFBasicHashRef ht
, uintptr_t *ptr
) {
709 __AssignWithWriteBarrier(&ht
->pointers
[ht
->bits
.hashes_offset
], ptr
);
713 // to expose the load factor, expose this function to customization
714 CF_INLINE CFIndex
__CFBasicHashGetCapacityForNumBuckets(CFConstBasicHashRef ht
, CFIndex num_buckets_idx
) {
715 return __CFBasicHashTableCapacities
[num_buckets_idx
];
718 CF_INLINE CFIndex
__CFBasicHashGetNumBucketsIndexForCapacity(CFConstBasicHashRef ht
, CFIndex capacity
) {
719 for (CFIndex idx
= 0; idx
< 64; idx
++) {
720 if (capacity
<= __CFBasicHashGetCapacityForNumBuckets(ht
, idx
)) return idx
;
726 CF_PRIVATE CFIndex
CFBasicHashGetNumBuckets(CFConstBasicHashRef ht
) {
727 return __CFBasicHashTableSizes
[ht
->bits
.num_buckets_idx
];
730 CF_PRIVATE CFIndex
CFBasicHashGetCapacity(CFConstBasicHashRef ht
) {
731 return __CFBasicHashGetCapacityForNumBuckets(ht
, ht
->bits
.num_buckets_idx
);
734 // In returned struct, .count is zero if the bucket is empty or deleted,
735 // and the .weak_key field indicates which. .idx is either the index of
736 // the found bucket or the index of the bucket which should be filled by
737 // an add operation. For a set or multiset, the .weak_key and .weak_value
739 CF_PRIVATE CFBasicHashBucket
CFBasicHashGetBucket(CFConstBasicHashRef ht
, CFIndex idx
) {
740 CFBasicHashBucket result
;
742 if (__CFBasicHashIsEmptyOrDeleted(ht
, idx
)) {
744 result
.weak_value
= 0;
747 result
.count
= (ht
->bits
.counts_offset
) ? __CFBasicHashGetSlotCount(ht
, idx
) : 1;
748 result
.weak_value
= __CFBasicHashGetValue(ht
, idx
);
749 result
.weak_key
= __CFBasicHashGetKey(ht
, idx
);
755 static uintptr_t __CFBasicHashFold(uintptr_t dividend
, uint8_t idx
) {
757 case 1: return dividend
% 3;
758 case 2: return dividend
% 7;
759 case 3: return dividend
% 13;
760 case 4: return dividend
% 23;
761 case 5: return dividend
% 41;
762 case 6: return dividend
% 71;
763 case 7: return dividend
% 127;
764 case 8: return dividend
% 191;
765 case 9: return dividend
% 251;
766 case 10: return dividend
% 383;
767 case 11: return dividend
% 631;
768 case 12: return dividend
% 1087;
769 case 13: return dividend
% 1723;
770 case 14: return dividend
% 2803;
771 case 15: return dividend
% 4523;
772 case 16: return dividend
% 7351;
773 case 17: return dividend
% 11959;
774 case 18: return dividend
% 19447;
775 case 19: return dividend
% 31231;
776 case 20: return dividend
% 50683;
777 case 21: return dividend
% 81919;
778 case 22: return dividend
% 132607;
779 case 23: return dividend
% 214519;
780 case 24: return dividend
% 346607;
781 case 25: return dividend
% 561109;
782 case 26: return dividend
% 907759;
783 case 27: return dividend
% 1468927;
784 case 28: return dividend
% 2376191;
785 case 29: return dividend
% 3845119;
786 case 30: return dividend
% 6221311;
787 case 31: return dividend
% 10066421;
788 case 32: return dividend
% 16287743;
789 case 33: return dividend
% 26354171;
790 case 34: return dividend
% 42641881;
791 case 35: return dividend
% 68996069;
792 case 36: return dividend
% 111638519;
793 case 37: return dividend
% 180634607;
794 case 38: return dividend
% 292272623;
795 case 39: return dividend
% 472907251;
803 #define FIND_BUCKET_NAME ___CFBasicHashFindBucket_Linear
804 #define FIND_BUCKET_HASH_STYLE 1
805 #define FIND_BUCKET_FOR_REHASH 0
806 #define FIND_BUCKET_FOR_INDIRECT_KEY 0
807 #include "CFBasicHashFindBucket.m"
809 #define FIND_BUCKET_NAME ___CFBasicHashFindBucket_Linear_NoCollision
810 #define FIND_BUCKET_HASH_STYLE 1
811 #define FIND_BUCKET_FOR_REHASH 1
812 #define FIND_BUCKET_FOR_INDIRECT_KEY 0
813 #include "CFBasicHashFindBucket.m"
815 #define FIND_BUCKET_NAME ___CFBasicHashFindBucket_Linear_Indirect
816 #define FIND_BUCKET_HASH_STYLE 1
817 #define FIND_BUCKET_FOR_REHASH 0
818 #define FIND_BUCKET_FOR_INDIRECT_KEY 1
819 #include "CFBasicHashFindBucket.m"
821 #define FIND_BUCKET_NAME ___CFBasicHashFindBucket_Linear_Indirect_NoCollision
822 #define FIND_BUCKET_HASH_STYLE 1
823 #define FIND_BUCKET_FOR_REHASH 1
824 #define FIND_BUCKET_FOR_INDIRECT_KEY 1
825 #include "CFBasicHashFindBucket.m"
827 #define FIND_BUCKET_NAME ___CFBasicHashFindBucket_Double
828 #define FIND_BUCKET_HASH_STYLE 2
829 #define FIND_BUCKET_FOR_REHASH 0
830 #define FIND_BUCKET_FOR_INDIRECT_KEY 0
831 #include "CFBasicHashFindBucket.m"
833 #define FIND_BUCKET_NAME ___CFBasicHashFindBucket_Double_NoCollision
834 #define FIND_BUCKET_HASH_STYLE 2
835 #define FIND_BUCKET_FOR_REHASH 1
836 #define FIND_BUCKET_FOR_INDIRECT_KEY 0
837 #include "CFBasicHashFindBucket.m"
839 #define FIND_BUCKET_NAME ___CFBasicHashFindBucket_Double_Indirect
840 #define FIND_BUCKET_HASH_STYLE 2
841 #define FIND_BUCKET_FOR_REHASH 0
842 #define FIND_BUCKET_FOR_INDIRECT_KEY 1
843 #include "CFBasicHashFindBucket.m"
845 #define FIND_BUCKET_NAME ___CFBasicHashFindBucket_Double_Indirect_NoCollision
846 #define FIND_BUCKET_HASH_STYLE 2
847 #define FIND_BUCKET_FOR_REHASH 1
848 #define FIND_BUCKET_FOR_INDIRECT_KEY 1
849 #include "CFBasicHashFindBucket.m"
851 #define FIND_BUCKET_NAME ___CFBasicHashFindBucket_Exponential
852 #define FIND_BUCKET_HASH_STYLE 3
853 #define FIND_BUCKET_FOR_REHASH 0
854 #define FIND_BUCKET_FOR_INDIRECT_KEY 0
855 #include "CFBasicHashFindBucket.m"
857 #define FIND_BUCKET_NAME ___CFBasicHashFindBucket_Exponential_NoCollision
858 #define FIND_BUCKET_HASH_STYLE 3
859 #define FIND_BUCKET_FOR_REHASH 1
860 #define FIND_BUCKET_FOR_INDIRECT_KEY 0
861 #include "CFBasicHashFindBucket.m"
863 #define FIND_BUCKET_NAME ___CFBasicHashFindBucket_Exponential_Indirect
864 #define FIND_BUCKET_HASH_STYLE 3
865 #define FIND_BUCKET_FOR_REHASH 0
866 #define FIND_BUCKET_FOR_INDIRECT_KEY 1
867 #include "CFBasicHashFindBucket.m"
869 #define FIND_BUCKET_NAME ___CFBasicHashFindBucket_Exponential_Indirect_NoCollision
870 #define FIND_BUCKET_HASH_STYLE 3
871 #define FIND_BUCKET_FOR_REHASH 1
872 #define FIND_BUCKET_FOR_INDIRECT_KEY 1
873 #include "CFBasicHashFindBucket.m"
876 CF_INLINE CFBasicHashBucket
__CFBasicHashFindBucket(CFConstBasicHashRef ht
, uintptr_t stack_key
) {
877 if (0 == ht
->bits
.num_buckets_idx
) {
878 CFBasicHashBucket result
= {kCFNotFound
, 0UL, 0UL, 0};
881 if (ht
->bits
.indirect_keys
) {
882 switch (ht
->bits
.hash_style
) {
883 case __kCFBasicHashLinearHashingValue
: return ___CFBasicHashFindBucket_Linear_Indirect(ht
, stack_key
);
884 case __kCFBasicHashDoubleHashingValue
: return ___CFBasicHashFindBucket_Double_Indirect(ht
, stack_key
);
885 case __kCFBasicHashExponentialHashingValue
: return ___CFBasicHashFindBucket_Exponential_Indirect(ht
, stack_key
);
888 switch (ht
->bits
.hash_style
) {
889 case __kCFBasicHashLinearHashingValue
: return ___CFBasicHashFindBucket_Linear(ht
, stack_key
);
890 case __kCFBasicHashDoubleHashingValue
: return ___CFBasicHashFindBucket_Double(ht
, stack_key
);
891 case __kCFBasicHashExponentialHashingValue
: return ___CFBasicHashFindBucket_Exponential(ht
, stack_key
);
895 CFBasicHashBucket result
= {kCFNotFound
, 0UL, 0UL, 0};
899 CF_INLINE CFIndex
__CFBasicHashFindBucket_NoCollision(CFConstBasicHashRef ht
, uintptr_t stack_key
, uintptr_t key_hash
) {
900 if (0 == ht
->bits
.num_buckets_idx
) {
903 if (ht
->bits
.indirect_keys
) {
904 switch (ht
->bits
.hash_style
) {
905 case __kCFBasicHashLinearHashingValue
: return ___CFBasicHashFindBucket_Linear_Indirect_NoCollision(ht
, stack_key
, key_hash
);
906 case __kCFBasicHashDoubleHashingValue
: return ___CFBasicHashFindBucket_Double_Indirect_NoCollision(ht
, stack_key
, key_hash
);
907 case __kCFBasicHashExponentialHashingValue
: return ___CFBasicHashFindBucket_Exponential_Indirect_NoCollision(ht
, stack_key
, key_hash
);
910 switch (ht
->bits
.hash_style
) {
911 case __kCFBasicHashLinearHashingValue
: return ___CFBasicHashFindBucket_Linear_NoCollision(ht
, stack_key
, key_hash
);
912 case __kCFBasicHashDoubleHashingValue
: return ___CFBasicHashFindBucket_Double_NoCollision(ht
, stack_key
, key_hash
);
913 case __kCFBasicHashExponentialHashingValue
: return ___CFBasicHashFindBucket_Exponential_NoCollision(ht
, stack_key
, key_hash
);
920 CF_PRIVATE CFBasicHashBucket
CFBasicHashFindBucket(CFConstBasicHashRef ht
, uintptr_t stack_key
) {
921 if (__CFBasicHashSubABZero
== stack_key
|| __CFBasicHashSubABOne
== stack_key
) {
922 CFBasicHashBucket result
= {kCFNotFound
, 0UL, 0UL, 0};
925 return __CFBasicHashFindBucket(ht
, stack_key
);
928 CF_PRIVATE
void CFBasicHashSuppressRC(CFBasicHashRef ht
) {
929 ht
->bits
.null_rc
= 1;
932 CF_PRIVATE
void CFBasicHashUnsuppressRC(CFBasicHashRef ht
) {
933 ht
->bits
.null_rc
= 0;
936 CF_PRIVATE CFOptionFlags
CFBasicHashGetFlags(CFConstBasicHashRef ht
) {
937 CFOptionFlags flags
= (ht
->bits
.hash_style
<< 13);
938 if (CFBasicHashHasStrongValues(ht
)) flags
|= kCFBasicHashStrongValues
;
939 if (CFBasicHashHasStrongKeys(ht
)) flags
|= kCFBasicHashStrongKeys
;
940 if (ht
->bits
.fast_grow
) flags
|= kCFBasicHashAggressiveGrowth
;
941 if (ht
->bits
.keys_offset
) flags
|= kCFBasicHashHasKeys
;
942 if (ht
->bits
.counts_offset
) flags
|= kCFBasicHashHasCounts
;
943 if (__CFBasicHashHasHashCache(ht
)) flags
|= kCFBasicHashHasHashCache
;
947 CF_PRIVATE CFIndex
CFBasicHashGetCount(CFConstBasicHashRef ht
) {
948 if (ht
->bits
.counts_offset
) {
950 CFIndex cnt
= (CFIndex
)__CFBasicHashTableSizes
[ht
->bits
.num_buckets_idx
];
951 for (CFIndex idx
= 0; idx
< cnt
; idx
++) {
952 total
+= __CFBasicHashGetSlotCount(ht
, idx
);
956 return (CFIndex
)ht
->bits
.used_buckets
;
959 CF_PRIVATE CFIndex
CFBasicHashGetCountOfKey(CFConstBasicHashRef ht
, uintptr_t stack_key
) {
960 if (__CFBasicHashSubABZero
== stack_key
|| __CFBasicHashSubABOne
== stack_key
) {
963 if (0L == ht
->bits
.used_buckets
) {
966 return __CFBasicHashFindBucket(ht
, stack_key
).count
;
969 CF_PRIVATE CFIndex
CFBasicHashGetCountOfValue(CFConstBasicHashRef ht
, uintptr_t stack_value
) {
970 if (__CFBasicHashSubABZero
== stack_value
) {
973 if (0L == ht
->bits
.used_buckets
) {
976 if (!(ht
->bits
.keys_offset
)) {
977 return __CFBasicHashFindBucket(ht
, stack_value
).count
;
979 __block CFIndex total
= 0L;
980 CFBasicHashApply(ht
, ^(CFBasicHashBucket bkt
) {
981 if ((stack_value
== bkt
.weak_value
) || __CFBasicHashTestEqualValue(ht
, bkt
.weak_value
, stack_value
)) total
+= bkt
.count
;
982 return (Boolean
)true;
987 CF_PRIVATE Boolean
CFBasicHashesAreEqual(CFConstBasicHashRef ht1
, CFConstBasicHashRef ht2
) {
988 CFIndex cnt1
= CFBasicHashGetCount(ht1
);
989 if (cnt1
!= CFBasicHashGetCount(ht2
)) return false;
990 if (0 == cnt1
) return true;
991 __block Boolean equal
= true;
992 CFBasicHashApply(ht1
, ^(CFBasicHashBucket bkt1
) {
993 CFBasicHashBucket bkt2
= __CFBasicHashFindBucket(ht2
, bkt1
.weak_key
);
994 if (bkt1
.count
!= bkt2
.count
) {
996 return (Boolean
)false;
998 if ((ht1
->bits
.keys_offset
) && (bkt1
.weak_value
!= bkt2
.weak_value
) && !__CFBasicHashTestEqualValue(ht1
, bkt1
.weak_value
, bkt2
.weak_value
)) {
1000 return (Boolean
)false;
1002 return (Boolean
)true;
1007 CF_PRIVATE
void CFBasicHashApply(CFConstBasicHashRef ht
, Boolean (^block
)(CFBasicHashBucket
)) {
1008 CFIndex used
= (CFIndex
)ht
->bits
.used_buckets
, cnt
= (CFIndex
)__CFBasicHashTableSizes
[ht
->bits
.num_buckets_idx
];
1009 for (CFIndex idx
= 0; 0 < used
&& idx
< cnt
; idx
++) {
1010 CFBasicHashBucket bkt
= CFBasicHashGetBucket(ht
, idx
);
1011 if (0 < bkt
.count
) {
1020 CF_PRIVATE
void CFBasicHashApplyIndexed(CFConstBasicHashRef ht
, CFRange range
, Boolean (^block
)(CFBasicHashBucket
)) {
1021 if (range
.length
< 0) HALT
;
1022 if (range
.length
== 0) return;
1023 CFIndex cnt
= (CFIndex
)__CFBasicHashTableSizes
[ht
->bits
.num_buckets_idx
];
1024 if (cnt
< range
.location
+ range
.length
) HALT
;
1025 for (CFIndex idx
= 0; idx
< range
.length
; idx
++) {
1026 CFBasicHashBucket bkt
= CFBasicHashGetBucket(ht
, range
.location
+ idx
);
1027 if (0 < bkt
.count
) {
1035 CF_PRIVATE
void CFBasicHashGetElements(CFConstBasicHashRef ht
, CFIndex bufferslen
, uintptr_t *weak_values
, uintptr_t *weak_keys
) {
1036 CFIndex used
= (CFIndex
)ht
->bits
.used_buckets
, cnt
= (CFIndex
)__CFBasicHashTableSizes
[ht
->bits
.num_buckets_idx
];
1038 for (CFIndex idx
= 0; 0 < used
&& idx
< cnt
&& offset
< bufferslen
; idx
++) {
1039 CFBasicHashBucket bkt
= CFBasicHashGetBucket(ht
, idx
);
1040 if (0 < bkt
.count
) {
1042 for (CFIndex cnt
= bkt
.count
; cnt
-- && offset
< bufferslen
;) {
1043 if (weak_values
) { weak_values
[offset
] = bkt
.weak_value
; }
1044 if (weak_keys
) { weak_keys
[offset
] = bkt
.weak_key
; }
1051 CF_PRIVATE
unsigned long __CFBasicHashFastEnumeration(CFConstBasicHashRef ht
, struct __objcFastEnumerationStateEquivalent2
*state
, void *stackbuffer
, unsigned long count
) {
1052 /* copy as many as count items over */
1053 if (0 == state
->state
) { /* first time */
1054 state
->mutationsPtr
= (unsigned long *)&ht
->bits
;
1056 state
->itemsPtr
= (unsigned long *)stackbuffer
;
1058 CFIndex used
= (CFIndex
)ht
->bits
.used_buckets
, cnt
= (CFIndex
)__CFBasicHashTableSizes
[ht
->bits
.num_buckets_idx
];
1059 for (CFIndex idx
= (CFIndex
)state
->state
; 0 < used
&& idx
< cnt
&& cntx
< (CFIndex
)count
; idx
++) {
1060 CFBasicHashBucket bkt
= CFBasicHashGetBucket(ht
, idx
);
1061 if (0 < bkt
.count
) {
1062 state
->itemsPtr
[cntx
++] = (unsigned long)bkt
.weak_key
;
1070 #if ENABLE_MEMORY_COUNTERS
1071 static volatile int64_t __CFBasicHashTotalCount
= 0ULL;
1072 static volatile int64_t __CFBasicHashTotalSize
= 0ULL;
1073 static volatile int64_t __CFBasicHashPeakCount
= 0ULL;
1074 static volatile int64_t __CFBasicHashPeakSize
= 0ULL;
1075 static volatile int32_t __CFBasicHashSizes
[64] = {0};
1078 static void __CFBasicHashDrain(CFBasicHashRef ht
, Boolean forFinalization
) {
1079 #if ENABLE_MEMORY_COUNTERS
1080 OSAtomicAdd64Barrier(-1 * (int64_t) CFBasicHashGetSize(ht
, true), & __CFBasicHashTotalSize
);
1083 CFIndex old_num_buckets
= __CFBasicHashTableSizes
[ht
->bits
.num_buckets_idx
];
1085 CFAllocatorRef allocator
= CFGetAllocator(ht
);
1086 Boolean nullify
= (!forFinalization
|| !CF_IS_COLLECTABLE_ALLOCATOR(allocator
));
1088 CFBasicHashValue
*old_values
= NULL
, *old_keys
= NULL
;
1089 void *old_counts
= NULL
;
1090 uintptr_t *old_hashes
= NULL
;
1092 old_values
= __CFBasicHashGetValues(ht
);
1093 if (nullify
) __CFBasicHashSetValues(ht
, NULL
);
1094 if (ht
->bits
.keys_offset
) {
1095 old_keys
= __CFBasicHashGetKeys(ht
);
1096 if (nullify
) __CFBasicHashSetKeys(ht
, NULL
);
1098 if (ht
->bits
.counts_offset
) {
1099 old_counts
= __CFBasicHashGetCounts(ht
);
1100 if (nullify
) __CFBasicHashSetCounts(ht
, NULL
);
1102 if (__CFBasicHashHasHashCache(ht
)) {
1103 old_hashes
= __CFBasicHashGetHashes(ht
);
1104 if (nullify
) __CFBasicHashSetHashes(ht
, NULL
);
1108 ht
->bits
.mutations
++;
1109 ht
->bits
.num_buckets_idx
= 0;
1110 ht
->bits
.used_buckets
= 0;
1111 ht
->bits
.deleted
= 0;
1114 for (CFIndex idx
= 0; idx
< old_num_buckets
; idx
++) {
1115 uintptr_t stack_value
= old_values
[idx
].neutral
;
1116 if (stack_value
!= 0UL && stack_value
!= ~0UL) {
1117 uintptr_t old_value
= stack_value
;
1118 if (__CFBasicHashSubABZero
== old_value
) old_value
= 0UL;
1119 if (__CFBasicHashSubABOne
== old_value
) old_value
= ~0UL;
1120 __CFBasicHashEjectValue(ht
, old_value
);
1122 uintptr_t old_key
= old_keys
[idx
].neutral
;
1123 if (__CFBasicHashSubABZero
== old_key
) old_key
= 0UL;
1124 if (__CFBasicHashSubABOne
== old_key
) old_key
= ~0UL;
1125 __CFBasicHashEjectKey(ht
, old_key
);
1130 if (!CF_IS_COLLECTABLE_ALLOCATOR(allocator
)) {
1131 CFAllocatorDeallocate(allocator
, old_values
);
1132 CFAllocatorDeallocate(allocator
, old_keys
);
1133 CFAllocatorDeallocate(allocator
, old_counts
);
1134 CFAllocatorDeallocate(allocator
, old_hashes
);
1137 #if ENABLE_MEMORY_COUNTERS
1138 int64_t size_now
= OSAtomicAdd64Barrier((int64_t) CFBasicHashGetSize(ht
, true), & __CFBasicHashTotalSize
);
1139 while (__CFBasicHashPeakSize
< size_now
&& !OSAtomicCompareAndSwap64Barrier(__CFBasicHashPeakSize
, size_now
, & __CFBasicHashPeakSize
));
1143 static void __CFBasicHashRehash(CFBasicHashRef ht
, CFIndex newItemCount
) {
1144 #if ENABLE_MEMORY_COUNTERS
1145 OSAtomicAdd64Barrier(-1 * (int64_t) CFBasicHashGetSize(ht
, true), & __CFBasicHashTotalSize
);
1146 OSAtomicAdd32Barrier(-1, &__CFBasicHashSizes
[ht
->bits
.num_buckets_idx
]);
1149 if (COCOA_HASHTABLE_REHASH_START_ENABLED()) COCOA_HASHTABLE_REHASH_START(ht
, CFBasicHashGetNumBuckets(ht
), CFBasicHashGetSize(ht
, true));
1151 CFIndex new_num_buckets_idx
= ht
->bits
.num_buckets_idx
;
1152 if (0 != newItemCount
) {
1153 if (newItemCount
< 0) newItemCount
= 0;
1154 CFIndex new_capacity_req
= ht
->bits
.used_buckets
+ newItemCount
;
1155 new_num_buckets_idx
= __CFBasicHashGetNumBucketsIndexForCapacity(ht
, new_capacity_req
);
1156 if (1 == newItemCount
&& ht
->bits
.fast_grow
) {
1157 new_num_buckets_idx
++;
1161 CFIndex new_num_buckets
= __CFBasicHashTableSizes
[new_num_buckets_idx
];
1162 CFIndex old_num_buckets
= __CFBasicHashTableSizes
[ht
->bits
.num_buckets_idx
];
1164 CFBasicHashValue
*new_values
= NULL
, *new_keys
= NULL
;
1165 void *new_counts
= NULL
;
1166 uintptr_t *new_hashes
= NULL
;
1168 if (0 < new_num_buckets
) {
1169 new_values
= (CFBasicHashValue
*)__CFBasicHashAllocateMemory(ht
, new_num_buckets
, sizeof(CFBasicHashValue
), CFBasicHashHasStrongValues(ht
), 0);
1170 if (!new_values
) HALT
;
1171 __SetLastAllocationEventName(new_values
, "CFBasicHash (value-store)");
1172 memset(new_values
, 0, new_num_buckets
* sizeof(CFBasicHashValue
));
1173 if (ht
->bits
.keys_offset
) {
1174 new_keys
= (CFBasicHashValue
*)__CFBasicHashAllocateMemory(ht
, new_num_buckets
, sizeof(CFBasicHashValue
), CFBasicHashHasStrongKeys(ht
), 0);
1175 if (!new_keys
) HALT
;
1176 __SetLastAllocationEventName(new_keys
, "CFBasicHash (key-store)");
1177 memset(new_keys
, 0, new_num_buckets
* sizeof(CFBasicHashValue
));
1179 if (ht
->bits
.counts_offset
) {
1180 new_counts
= (uintptr_t *)__CFBasicHashAllocateMemory(ht
, new_num_buckets
, (1 << ht
->bits
.counts_width
), false, false);
1181 if (!new_counts
) HALT
;
1182 __SetLastAllocationEventName(new_counts
, "CFBasicHash (count-store)");
1183 memset(new_counts
, 0, new_num_buckets
* (1 << ht
->bits
.counts_width
));
1185 if (__CFBasicHashHasHashCache(ht
)) {
1186 new_hashes
= (uintptr_t *)__CFBasicHashAllocateMemory(ht
, new_num_buckets
, sizeof(uintptr_t), false, false);
1187 if (!new_hashes
) HALT
;
1188 __SetLastAllocationEventName(new_hashes
, "CFBasicHash (hash-store)");
1189 memset(new_hashes
, 0, new_num_buckets
* sizeof(uintptr_t));
1193 ht
->bits
.num_buckets_idx
= new_num_buckets_idx
;
1194 ht
->bits
.deleted
= 0;
1196 CFBasicHashValue
*old_values
= NULL
, *old_keys
= NULL
;
1197 void *old_counts
= NULL
;
1198 uintptr_t *old_hashes
= NULL
;
1200 old_values
= __CFBasicHashGetValues(ht
);
1201 __CFBasicHashSetValues(ht
, new_values
);
1202 if (ht
->bits
.keys_offset
) {
1203 old_keys
= __CFBasicHashGetKeys(ht
);
1204 __CFBasicHashSetKeys(ht
, new_keys
);
1206 if (ht
->bits
.counts_offset
) {
1207 old_counts
= __CFBasicHashGetCounts(ht
);
1208 __CFBasicHashSetCounts(ht
, new_counts
);
1210 if (__CFBasicHashHasHashCache(ht
)) {
1211 old_hashes
= __CFBasicHashGetHashes(ht
);
1212 __CFBasicHashSetHashes(ht
, new_hashes
);
1215 if (0 < old_num_buckets
) {
1216 for (CFIndex idx
= 0; idx
< old_num_buckets
; idx
++) {
1217 uintptr_t stack_value
= old_values
[idx
].neutral
;
1218 if (stack_value
!= 0UL && stack_value
!= ~0UL) {
1219 if (__CFBasicHashSubABZero
== stack_value
) stack_value
= 0UL;
1220 if (__CFBasicHashSubABOne
== stack_value
) stack_value
= ~0UL;
1221 uintptr_t stack_key
= stack_value
;
1222 if (ht
->bits
.keys_offset
) {
1223 stack_key
= old_keys
[idx
].neutral
;
1224 if (__CFBasicHashSubABZero
== stack_key
) stack_key
= 0UL;
1225 if (__CFBasicHashSubABOne
== stack_key
) stack_key
= ~0UL;
1227 if (ht
->bits
.indirect_keys
) {
1228 stack_key
= __CFBasicHashGetIndirectKey(ht
, stack_value
);
1230 CFIndex bkt_idx
= __CFBasicHashFindBucket_NoCollision(ht
, stack_key
, old_hashes
? old_hashes
[idx
] : 0UL);
1231 __CFBasicHashSetValue(ht
, bkt_idx
, stack_value
, false, false);
1233 __CFBasicHashSetKey(ht
, bkt_idx
, stack_key
, false, false);
1236 switch (ht
->bits
.counts_width
) {
1237 case 0: ((uint8_t *)new_counts
)[bkt_idx
] = ((uint8_t *)old_counts
)[idx
]; break;
1238 case 1: ((uint16_t *)new_counts
)[bkt_idx
] = ((uint16_t *)old_counts
)[idx
]; break;
1239 case 2: ((uint32_t *)new_counts
)[bkt_idx
] = ((uint32_t *)old_counts
)[idx
]; break;
1240 case 3: ((uint64_t *)new_counts
)[bkt_idx
] = ((uint64_t *)old_counts
)[idx
]; break;
1244 new_hashes
[bkt_idx
] = old_hashes
[idx
];
1250 CFAllocatorRef allocator
= CFGetAllocator(ht
);
1251 if (!CF_IS_COLLECTABLE_ALLOCATOR(allocator
)) {
1252 CFAllocatorDeallocate(allocator
, old_values
);
1253 CFAllocatorDeallocate(allocator
, old_keys
);
1254 CFAllocatorDeallocate(allocator
, old_counts
);
1255 CFAllocatorDeallocate(allocator
, old_hashes
);
1258 if (COCOA_HASHTABLE_REHASH_END_ENABLED()) COCOA_HASHTABLE_REHASH_END(ht
, CFBasicHashGetNumBuckets(ht
), CFBasicHashGetSize(ht
, true));
1260 #if ENABLE_MEMORY_COUNTERS
1261 int64_t size_now
= OSAtomicAdd64Barrier((int64_t) CFBasicHashGetSize(ht
, true), &__CFBasicHashTotalSize
);
1262 while (__CFBasicHashPeakSize
< size_now
&& !OSAtomicCompareAndSwap64Barrier(__CFBasicHashPeakSize
, size_now
, & __CFBasicHashPeakSize
));
1263 OSAtomicAdd32Barrier(1, &__CFBasicHashSizes
[ht
->bits
.num_buckets_idx
]);
1267 CF_PRIVATE
void CFBasicHashSetCapacity(CFBasicHashRef ht
, CFIndex capacity
) {
1268 if (!CFBasicHashIsMutable(ht
)) HALT
;
1269 if (ht
->bits
.used_buckets
< capacity
) {
1270 ht
->bits
.mutations
++;
1271 __CFBasicHashRehash(ht
, capacity
- ht
->bits
.used_buckets
);
1275 static void __CFBasicHashAddValue(CFBasicHashRef ht
, CFIndex bkt_idx
, uintptr_t stack_key
, uintptr_t stack_value
) {
1276 ht
->bits
.mutations
++;
1277 if (CFBasicHashGetCapacity(ht
) < ht
->bits
.used_buckets
+ 1) {
1278 __CFBasicHashRehash(ht
, 1);
1279 bkt_idx
= __CFBasicHashFindBucket_NoCollision(ht
, stack_key
, 0);
1280 } else if (__CFBasicHashIsDeleted(ht
, bkt_idx
)) {
1283 uintptr_t key_hash
= 0;
1284 if (__CFBasicHashHasHashCache(ht
)) {
1285 key_hash
= __CFBasicHashHashKey(ht
, stack_key
);
1287 stack_value
= __CFBasicHashImportValue(ht
, stack_value
);
1288 if (ht
->bits
.keys_offset
) {
1289 stack_key
= __CFBasicHashImportKey(ht
, stack_key
);
1291 __CFBasicHashSetValue(ht
, bkt_idx
, stack_value
, false, false);
1292 if (ht
->bits
.keys_offset
) {
1293 __CFBasicHashSetKey(ht
, bkt_idx
, stack_key
, false, false);
1295 if (ht
->bits
.counts_offset
) {
1296 __CFBasicHashIncSlotCount(ht
, bkt_idx
);
1298 if (__CFBasicHashHasHashCache(ht
)) {
1299 __CFBasicHashGetHashes(ht
)[bkt_idx
] = key_hash
;
1301 ht
->bits
.used_buckets
++;
1304 static void __CFBasicHashReplaceValue(CFBasicHashRef ht
, CFIndex bkt_idx
, uintptr_t stack_key
, uintptr_t stack_value
) {
1305 ht
->bits
.mutations
++;
1306 stack_value
= __CFBasicHashImportValue(ht
, stack_value
);
1307 if (ht
->bits
.keys_offset
) {
1308 stack_key
= __CFBasicHashImportKey(ht
, stack_key
);
1310 __CFBasicHashSetValue(ht
, bkt_idx
, stack_value
, false, false);
1311 if (ht
->bits
.keys_offset
) {
1312 __CFBasicHashSetKey(ht
, bkt_idx
, stack_key
, false, false);
1316 static void __CFBasicHashRemoveValue(CFBasicHashRef ht
, CFIndex bkt_idx
) {
1317 ht
->bits
.mutations
++;
1318 __CFBasicHashSetValue(ht
, bkt_idx
, ~0UL, false, true);
1319 if (ht
->bits
.keys_offset
) {
1320 __CFBasicHashSetKey(ht
, bkt_idx
, ~0UL, false, true);
1322 if (ht
->bits
.counts_offset
) {
1323 __CFBasicHashDecSlotCount(ht
, bkt_idx
);
1325 if (__CFBasicHashHasHashCache(ht
)) {
1326 __CFBasicHashGetHashes(ht
)[bkt_idx
] = 0;
1328 ht
->bits
.used_buckets
--;
1330 Boolean do_shrink
= false;
1331 if (ht
->bits
.fast_grow
) { // == slow shrink
1332 do_shrink
= (5 < ht
->bits
.num_buckets_idx
&& ht
->bits
.used_buckets
< __CFBasicHashGetCapacityForNumBuckets(ht
, ht
->bits
.num_buckets_idx
- 5));
1334 do_shrink
= (2 < ht
->bits
.num_buckets_idx
&& ht
->bits
.used_buckets
< __CFBasicHashGetCapacityForNumBuckets(ht
, ht
->bits
.num_buckets_idx
- 2));
1337 __CFBasicHashRehash(ht
, -1);
1340 do_shrink
= (0 == ht
->bits
.deleted
); // .deleted roll-over
1341 CFIndex num_buckets
= __CFBasicHashTableSizes
[ht
->bits
.num_buckets_idx
];
1342 do_shrink
= do_shrink
|| ((20 <= num_buckets
) && (num_buckets
/ 4 <= ht
->bits
.deleted
));
1344 __CFBasicHashRehash(ht
, 0);
1348 CF_PRIVATE Boolean
CFBasicHashAddValue(CFBasicHashRef ht
, uintptr_t stack_key
, uintptr_t stack_value
) {
1349 if (!CFBasicHashIsMutable(ht
)) HALT
;
1350 if (__CFBasicHashSubABZero
== stack_key
) HALT
;
1351 if (__CFBasicHashSubABOne
== stack_key
) HALT
;
1352 if (__CFBasicHashSubABZero
== stack_value
) HALT
;
1353 if (__CFBasicHashSubABOne
== stack_value
) HALT
;
1354 CFBasicHashBucket bkt
= __CFBasicHashFindBucket(ht
, stack_key
);
1355 if (0 < bkt
.count
) {
1356 ht
->bits
.mutations
++;
1357 if (ht
->bits
.counts_offset
&& bkt
.count
< LONG_MAX
) { // if not yet as large as a CFIndex can be... otherwise clamp and do nothing
1358 __CFBasicHashIncSlotCount(ht
, bkt
.idx
);
1362 __CFBasicHashAddValue(ht
, bkt
.idx
, stack_key
, stack_value
);
1368 CF_PRIVATE
void CFBasicHashReplaceValue(CFBasicHashRef ht
, uintptr_t stack_key
, uintptr_t stack_value
) {
1369 if (!CFBasicHashIsMutable(ht
)) HALT
;
1370 if (__CFBasicHashSubABZero
== stack_key
) HALT
;
1371 if (__CFBasicHashSubABOne
== stack_key
) HALT
;
1372 if (__CFBasicHashSubABZero
== stack_value
) HALT
;
1373 if (__CFBasicHashSubABOne
== stack_value
) HALT
;
1374 CFBasicHashBucket bkt
= __CFBasicHashFindBucket(ht
, stack_key
);
1375 if (0 < bkt
.count
) {
1376 __CFBasicHashReplaceValue(ht
, bkt
.idx
, stack_key
, stack_value
);
1380 CF_PRIVATE
void CFBasicHashSetValue(CFBasicHashRef ht
, uintptr_t stack_key
, uintptr_t stack_value
) {
1381 if (!CFBasicHashIsMutable(ht
)) HALT
;
1382 if (__CFBasicHashSubABZero
== stack_key
) HALT
;
1383 if (__CFBasicHashSubABOne
== stack_key
) HALT
;
1384 if (__CFBasicHashSubABZero
== stack_value
) HALT
;
1385 if (__CFBasicHashSubABOne
== stack_value
) HALT
;
1386 CFBasicHashBucket bkt
= __CFBasicHashFindBucket(ht
, stack_key
);
1387 if (0 < bkt
.count
) {
1388 __CFBasicHashReplaceValue(ht
, bkt
.idx
, stack_key
, stack_value
);
1390 __CFBasicHashAddValue(ht
, bkt
.idx
, stack_key
, stack_value
);
1394 CF_PRIVATE CFIndex
CFBasicHashRemoveValue(CFBasicHashRef ht
, uintptr_t stack_key
) {
1395 if (!CFBasicHashIsMutable(ht
)) HALT
;
1396 if (__CFBasicHashSubABZero
== stack_key
|| __CFBasicHashSubABOne
== stack_key
) return 0;
1397 CFBasicHashBucket bkt
= __CFBasicHashFindBucket(ht
, stack_key
);
1398 if (1 < bkt
.count
) {
1399 ht
->bits
.mutations
++;
1400 if (ht
->bits
.counts_offset
&& bkt
.count
< LONG_MAX
) { // if not as large as a CFIndex can be... otherwise clamp and do nothing
1401 __CFBasicHashDecSlotCount(ht
, bkt
.idx
);
1403 } else if (0 < bkt
.count
) {
1404 __CFBasicHashRemoveValue(ht
, bkt
.idx
);
1409 CF_PRIVATE CFIndex
CFBasicHashRemoveValueAtIndex(CFBasicHashRef ht
, CFIndex idx
) {
1410 if (!CFBasicHashIsMutable(ht
)) HALT
;
1411 CFBasicHashBucket bkt
= CFBasicHashGetBucket(ht
, idx
);
1412 if (1 < bkt
.count
) {
1413 ht
->bits
.mutations
++;
1414 if (ht
->bits
.counts_offset
&& bkt
.count
< LONG_MAX
) { // if not as large as a CFIndex can be... otherwise clamp and do nothing
1415 __CFBasicHashDecSlotCount(ht
, bkt
.idx
);
1417 } else if (0 < bkt
.count
) {
1418 __CFBasicHashRemoveValue(ht
, bkt
.idx
);
1423 CF_PRIVATE
void CFBasicHashRemoveAllValues(CFBasicHashRef ht
) {
1424 if (!CFBasicHashIsMutable(ht
)) HALT
;
1425 if (0 == ht
->bits
.num_buckets_idx
) return;
1426 __CFBasicHashDrain(ht
, false);
1429 CF_PRIVATE Boolean
CFBasicHashAddIntValueAndInc(CFBasicHashRef ht
, uintptr_t stack_key
, uintptr_t int_value
) {
1430 if (!CFBasicHashIsMutable(ht
)) HALT
;
1431 if (__CFBasicHashSubABZero
== stack_key
) HALT
;
1432 if (__CFBasicHashSubABOne
== stack_key
) HALT
;
1433 if (__CFBasicHashSubABZero
== int_value
) HALT
;
1434 if (__CFBasicHashSubABOne
== int_value
) HALT
;
1435 CFBasicHashBucket bkt
= __CFBasicHashFindBucket(ht
, stack_key
);
1436 if (0 < bkt
.count
) {
1437 ht
->bits
.mutations
++;
1439 // must rehash before renumbering
1440 if (CFBasicHashGetCapacity(ht
) < ht
->bits
.used_buckets
+ 1) {
1441 __CFBasicHashRehash(ht
, 1);
1442 bkt
.idx
= __CFBasicHashFindBucket_NoCollision(ht
, stack_key
, 0);
1444 CFIndex cnt
= (CFIndex
)__CFBasicHashTableSizes
[ht
->bits
.num_buckets_idx
];
1445 for (CFIndex idx
= 0; idx
< cnt
; idx
++) {
1446 if (!__CFBasicHashIsEmptyOrDeleted(ht
, idx
)) {
1447 uintptr_t stack_value
= __CFBasicHashGetValue(ht
, idx
);
1448 if (int_value
<= stack_value
) {
1450 __CFBasicHashSetValue(ht
, idx
, stack_value
, true, false);
1451 ht
->bits
.mutations
++;
1455 __CFBasicHashAddValue(ht
, bkt
.idx
, stack_key
, int_value
);
1461 CF_PRIVATE
void CFBasicHashRemoveIntValueAndDec(CFBasicHashRef ht
, uintptr_t int_value
) {
1462 if (!CFBasicHashIsMutable(ht
)) HALT
;
1463 if (__CFBasicHashSubABZero
== int_value
) HALT
;
1464 if (__CFBasicHashSubABOne
== int_value
) HALT
;
1465 uintptr_t bkt_idx
= ~0UL;
1466 CFIndex cnt
= (CFIndex
)__CFBasicHashTableSizes
[ht
->bits
.num_buckets_idx
];
1467 for (CFIndex idx
= 0; idx
< cnt
; idx
++) {
1468 if (!__CFBasicHashIsEmptyOrDeleted(ht
, idx
)) {
1469 uintptr_t stack_value
= __CFBasicHashGetValue(ht
, idx
);
1470 if (int_value
== stack_value
) {
1473 if (int_value
< stack_value
) {
1475 __CFBasicHashSetValue(ht
, idx
, stack_value
, true, false);
1476 ht
->bits
.mutations
++;
1480 __CFBasicHashRemoveValue(ht
, bkt_idx
);
1483 CF_PRIVATE
size_t CFBasicHashGetSize(CFConstBasicHashRef ht
, Boolean total
) {
1484 size_t size
= sizeof(struct __CFBasicHash
);
1485 if (ht
->bits
.keys_offset
) size
+= sizeof(CFBasicHashValue
*);
1486 if (ht
->bits
.counts_offset
) size
+= sizeof(void *);
1487 if (__CFBasicHashHasHashCache(ht
)) size
+= sizeof(uintptr_t *);
1489 CFIndex num_buckets
= __CFBasicHashTableSizes
[ht
->bits
.num_buckets_idx
];
1490 if (0 < num_buckets
) {
1491 size
+= malloc_size(__CFBasicHashGetValues(ht
));
1492 if (ht
->bits
.keys_offset
) size
+= malloc_size(__CFBasicHashGetKeys(ht
));
1493 if (ht
->bits
.counts_offset
) size
+= malloc_size(__CFBasicHashGetCounts(ht
));
1494 if (__CFBasicHashHasHashCache(ht
)) size
+= malloc_size(__CFBasicHashGetHashes(ht
));
1500 CF_PRIVATE CFStringRef
CFBasicHashCopyDescription(CFConstBasicHashRef ht
, Boolean detailed
, CFStringRef prefix
, CFStringRef entryPrefix
, Boolean describeElements
) {
1501 CFMutableStringRef result
= CFStringCreateMutable(kCFAllocatorSystemDefault
, 0);
1502 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
));
1504 const char *cb_type
= "custom";
1505 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
);
1506 CFStringAppendFormat(result
, NULL
, CFSTR("%@num bucket index = %d, num buckets = %ld, capacity = %ld, num buckets used = %u,\n"), prefix
, ht
->bits
.num_buckets_idx
, CFBasicHashGetNumBuckets(ht
), (long)CFBasicHashGetCapacity(ht
), ht
->bits
.used_buckets
);
1507 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"));
1508 CFStringAppendFormat(result
, NULL
, CFSTR("%@num mutations = %ld, num deleted = %ld, size = %ld, total size = %ld,\n"), prefix
, (long)ht
->bits
.mutations
, (long)ht
->bits
.deleted
, CFBasicHashGetSize(ht
, false), CFBasicHashGetSize(ht
, true));
1509 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
));
1511 CFStringAppendFormat(result
, NULL
, CFSTR("%@entries =>\n"), prefix
);
1512 CFBasicHashApply(ht
, ^(CFBasicHashBucket bkt
) {
1513 CFStringRef vDesc
= NULL
, kDesc
= NULL
;
1514 if (!describeElements
) {
1515 vDesc
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("<%p>"), (void *)bkt
.weak_value
);
1516 if (ht
->bits
.keys_offset
) {
1517 kDesc
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("<%p>"), (void *)bkt
.weak_key
);
1520 vDesc
= __CFBasicHashDescValue(ht
, bkt
.weak_value
);
1521 if (ht
->bits
.keys_offset
) {
1522 kDesc
= __CFBasicHashDescKey(ht
, bkt
.weak_key
);
1525 if (ht
->bits
.keys_offset
&& ht
->bits
.counts_offset
) {
1526 CFStringAppendFormat(result
, NULL
, CFSTR("%@%ld : %@ = %@ (%ld)\n"), entryPrefix
, bkt
.idx
, kDesc
, vDesc
, bkt
.count
);
1527 } else if (ht
->bits
.keys_offset
) {
1528 CFStringAppendFormat(result
, NULL
, CFSTR("%@%ld : %@ = %@\n"), entryPrefix
, bkt
.idx
, kDesc
, vDesc
);
1529 } else if (ht
->bits
.counts_offset
) {
1530 CFStringAppendFormat(result
, NULL
, CFSTR("%@%ld : %@ (%ld)\n"), entryPrefix
, bkt
.idx
, vDesc
, bkt
.count
);
1532 CFStringAppendFormat(result
, NULL
, CFSTR("%@%ld : %@\n"), entryPrefix
, bkt
.idx
, vDesc
);
1534 if (kDesc
) CFRelease(kDesc
);
1535 if (vDesc
) CFRelease(vDesc
);
1536 return (Boolean
)true;
1538 CFStringAppendFormat(result
, NULL
, CFSTR("%@}\n"), prefix
);
1542 CF_PRIVATE
void CFBasicHashShow(CFConstBasicHashRef ht
) {
1543 CFStringRef str
= CFBasicHashCopyDescription(ht
, true, CFSTR(""), CFSTR("\t"), false);
1548 CF_PRIVATE Boolean
__CFBasicHashEqual(CFTypeRef cf1
, CFTypeRef cf2
) {
1549 CFBasicHashRef ht1
= (CFBasicHashRef
)cf1
;
1550 CFBasicHashRef ht2
= (CFBasicHashRef
)cf2
;
1551 //#warning this used to require that the key and value equal callbacks were pointer identical
1552 return CFBasicHashesAreEqual(ht1
, ht2
);
1555 CF_PRIVATE CFHashCode
__CFBasicHashHash(CFTypeRef cf
) {
1556 CFBasicHashRef ht
= (CFBasicHashRef
)cf
;
1557 return CFBasicHashGetCount(ht
);
1560 CF_PRIVATE CFStringRef
__CFBasicHashCopyDescription(CFTypeRef cf
) {
1561 CFBasicHashRef ht
= (CFBasicHashRef
)cf
;
1562 CFStringRef desc
= CFBasicHashCopyDescription(ht
, false, CFSTR(""), CFSTR("\t"), true);
1563 CFStringRef result
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("<CFBasicHash %p [%p]>%@"), cf
, CFGetAllocator(cf
), desc
);
1568 CF_PRIVATE
void __CFBasicHashDeallocate(CFTypeRef cf
) {
1569 CFBasicHashRef ht
= (CFBasicHashRef
)cf
;
1570 if (ht
->bits
.finalized
) HALT
;
1571 ht
->bits
.finalized
= 1;
1572 __CFBasicHashDrain(ht
, true);
1573 #if ENABLE_MEMORY_COUNTERS
1574 OSAtomicAdd64Barrier(-1, &__CFBasicHashTotalCount
);
1575 OSAtomicAdd32Barrier(-1, &__CFBasicHashSizes
[ht
->bits
.num_buckets_idx
]);
1579 static CFTypeID __kCFBasicHashTypeID
= _kCFRuntimeNotATypeID
;
1581 static const CFRuntimeClass __CFBasicHashClass
= {
1582 _kCFRuntimeScannedObject
,
1586 __CFBasicHashDeallocate
,
1590 __CFBasicHashCopyDescription
1593 CF_PRIVATE CFTypeID
CFBasicHashGetTypeID(void) {
1594 if (_kCFRuntimeNotATypeID
== __kCFBasicHashTypeID
) __kCFBasicHashTypeID
= _CFRuntimeRegisterClass(&__CFBasicHashClass
);
1595 return __kCFBasicHashTypeID
;
1598 CF_PRIVATE CFBasicHashRef
CFBasicHashCreate(CFAllocatorRef allocator
, CFOptionFlags flags
, const CFBasicHashCallbacks
*cb
) {
1599 size_t size
= sizeof(struct __CFBasicHash
) - sizeof(CFRuntimeBase
);
1600 if (flags
& kCFBasicHashHasKeys
) size
+= sizeof(CFBasicHashValue
*); // keys
1601 if (flags
& kCFBasicHashHasCounts
) size
+= sizeof(void *); // counts
1602 if (flags
& kCFBasicHashHasHashCache
) size
+= sizeof(uintptr_t *); // hashes
1603 CFBasicHashRef ht
= (CFBasicHashRef
)_CFRuntimeCreateInstance(allocator
, CFBasicHashGetTypeID(), size
, NULL
);
1604 if (NULL
== ht
) return NULL
;
1606 ht
->bits
.finalized
= 0;
1607 ht
->bits
.hash_style
= (flags
>> 13) & 0x3;
1608 ht
->bits
.fast_grow
= (flags
& kCFBasicHashAggressiveGrowth
) ? 1 : 0;
1609 ht
->bits
.counts_width
= 0;
1610 ht
->bits
.strong_values
= (flags
& kCFBasicHashStrongValues
) ? 1 : 0;
1611 ht
->bits
.strong_keys
= (flags
& kCFBasicHashStrongKeys
) ? 1 : 0;
1612 ht
->bits
.weak_values
= (flags
& kCFBasicHashWeakValues
) ? 1 : 0;
1613 ht
->bits
.weak_keys
= (flags
& kCFBasicHashWeakKeys
) ? 1 : 0;
1614 ht
->bits
.int_values
= (flags
& kCFBasicHashIntegerValues
) ? 1 : 0;
1615 ht
->bits
.int_keys
= (flags
& kCFBasicHashIntegerKeys
) ? 1 : 0;
1616 ht
->bits
.indirect_keys
= (flags
& kCFBasicHashIndirectKeys
) ? 1 : 0;
1617 ht
->bits
.num_buckets_idx
= 0;
1618 ht
->bits
.used_buckets
= 0;
1619 ht
->bits
.deleted
= 0;
1620 ht
->bits
.mutations
= 1;
1622 if (ht
->bits
.strong_values
&& ht
->bits
.weak_values
) HALT
;
1623 if (ht
->bits
.strong_values
&& ht
->bits
.int_values
) HALT
;
1624 if (ht
->bits
.strong_keys
&& ht
->bits
.weak_keys
) HALT
;
1625 if (ht
->bits
.strong_keys
&& ht
->bits
.int_keys
) HALT
;
1626 if (ht
->bits
.weak_values
&& ht
->bits
.int_values
) HALT
;
1627 if (ht
->bits
.weak_keys
&& ht
->bits
.int_keys
) HALT
;
1628 if (ht
->bits
.indirect_keys
&& ht
->bits
.strong_keys
) HALT
;
1629 if (ht
->bits
.indirect_keys
&& ht
->bits
.weak_keys
) HALT
;
1630 if (ht
->bits
.indirect_keys
&& ht
->bits
.int_keys
) HALT
;
1632 uint64_t offset
= 1;
1633 ht
->bits
.keys_offset
= (flags
& kCFBasicHashHasKeys
) ? offset
++ : 0;
1634 ht
->bits
.counts_offset
= (flags
& kCFBasicHashHasCounts
) ? offset
++ : 0;
1635 ht
->bits
.hashes_offset
= (flags
& kCFBasicHashHasHashCache
) ? offset
++ : 0;
1637 #if DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
1638 ht
->bits
.hashes_offset
= 0;
1639 ht
->bits
.strong_values
= 0;
1640 ht
->bits
.strong_keys
= 0;
1641 ht
->bits
.weak_values
= 0;
1642 ht
->bits
.weak_keys
= 0;
1645 ht
->bits
.__kret
= CFBasicHashGetPtrIndex((void *)cb
->retainKey
);
1646 ht
->bits
.__vret
= CFBasicHashGetPtrIndex((void *)cb
->retainValue
);
1647 ht
->bits
.__krel
= CFBasicHashGetPtrIndex((void *)cb
->releaseKey
);
1648 ht
->bits
.__vrel
= CFBasicHashGetPtrIndex((void *)cb
->releaseValue
);
1649 ht
->bits
.__kdes
= CFBasicHashGetPtrIndex((void *)cb
->copyKeyDescription
);
1650 ht
->bits
.__vdes
= CFBasicHashGetPtrIndex((void *)cb
->copyValueDescription
);
1651 ht
->bits
.__kequ
= CFBasicHashGetPtrIndex((void *)cb
->equateKeys
);
1652 ht
->bits
.__vequ
= CFBasicHashGetPtrIndex((void *)cb
->equateValues
);
1653 ht
->bits
.__khas
= CFBasicHashGetPtrIndex((void *)cb
->hashKey
);
1654 ht
->bits
.__kget
= CFBasicHashGetPtrIndex((void *)cb
->getIndirectKey
);
1656 for (CFIndex idx
= 0; idx
< offset
; idx
++) {
1657 ht
->pointers
[idx
] = NULL
;
1660 #if ENABLE_MEMORY_COUNTERS
1661 int64_t size_now
= OSAtomicAdd64Barrier((int64_t) CFBasicHashGetSize(ht
, true), & __CFBasicHashTotalSize
);
1662 while (__CFBasicHashPeakSize
< size_now
&& !OSAtomicCompareAndSwap64Barrier(__CFBasicHashPeakSize
, size_now
, & __CFBasicHashPeakSize
));
1663 int64_t count_now
= OSAtomicAdd64Barrier(1, & __CFBasicHashTotalCount
);
1664 while (__CFBasicHashPeakCount
< count_now
&& !OSAtomicCompareAndSwap64Barrier(__CFBasicHashPeakCount
, count_now
, & __CFBasicHashPeakCount
));
1665 OSAtomicAdd32Barrier(1, &__CFBasicHashSizes
[ht
->bits
.num_buckets_idx
]);
1671 CF_PRIVATE CFBasicHashRef
CFBasicHashCreateCopy(CFAllocatorRef allocator
, CFConstBasicHashRef src_ht
) {
1672 size_t size
= CFBasicHashGetSize(src_ht
, false) - sizeof(CFRuntimeBase
);
1673 CFIndex new_num_buckets
= __CFBasicHashTableSizes
[src_ht
->bits
.num_buckets_idx
];
1674 CFBasicHashValue
*new_values
= NULL
, *new_keys
= NULL
;
1675 void *new_counts
= NULL
;
1676 uintptr_t *new_hashes
= NULL
;
1678 if (0 < new_num_buckets
) {
1679 Boolean strongValues
= CFBasicHashHasStrongValues(src_ht
) && !(kCFUseCollectableAllocator
&& !CF_IS_COLLECTABLE_ALLOCATOR(allocator
));
1680 Boolean strongKeys
= CFBasicHashHasStrongKeys(src_ht
) && !(kCFUseCollectableAllocator
&& !CF_IS_COLLECTABLE_ALLOCATOR(allocator
));
1681 new_values
= (CFBasicHashValue
*)__CFBasicHashAllocateMemory2(allocator
, new_num_buckets
, sizeof(CFBasicHashValue
), strongValues
, 0);
1682 if (!new_values
) return NULL
; // in this unusual circumstance, leak previously allocated blocks for now
1683 __SetLastAllocationEventName(new_values
, "CFBasicHash (value-store)");
1684 if (src_ht
->bits
.keys_offset
) {
1685 new_keys
= (CFBasicHashValue
*)__CFBasicHashAllocateMemory2(allocator
, new_num_buckets
, sizeof(CFBasicHashValue
), strongKeys
, false);
1686 if (!new_keys
) return NULL
; // in this unusual circumstance, leak previously allocated blocks for now
1687 __SetLastAllocationEventName(new_keys
, "CFBasicHash (key-store)");
1689 if (src_ht
->bits
.counts_offset
) {
1690 new_counts
= (uintptr_t *)__CFBasicHashAllocateMemory2(allocator
, new_num_buckets
, (1 << src_ht
->bits
.counts_width
), false, false);
1691 if (!new_counts
) return NULL
; // in this unusual circumstance, leak previously allocated blocks for now
1692 __SetLastAllocationEventName(new_counts
, "CFBasicHash (count-store)");
1694 if (__CFBasicHashHasHashCache(src_ht
)) {
1695 new_hashes
= (uintptr_t *)__CFBasicHashAllocateMemory2(allocator
, new_num_buckets
, sizeof(uintptr_t), false, false);
1696 if (!new_hashes
) return NULL
; // in this unusual circumstance, leak previously allocated blocks for now
1697 __SetLastAllocationEventName(new_hashes
, "CFBasicHash (hash-store)");
1701 CFBasicHashRef ht
= (CFBasicHashRef
)_CFRuntimeCreateInstance(allocator
, CFBasicHashGetTypeID(), size
, NULL
);
1702 if (NULL
== ht
) return NULL
; // in this unusual circumstance, leak previously allocated blocks for now
1704 memmove((uint8_t *)ht
+ sizeof(CFRuntimeBase
), (uint8_t *)src_ht
+ sizeof(CFRuntimeBase
), sizeof(ht
->bits
));
1705 if (kCFUseCollectableAllocator
&& !CF_IS_COLLECTABLE_ALLOCATOR(allocator
)) {
1706 ht
->bits
.strong_values
= 0;
1707 ht
->bits
.strong_keys
= 0;
1708 ht
->bits
.weak_values
= 0;
1709 ht
->bits
.weak_keys
= 0;
1711 ht
->bits
.finalized
= 0;
1712 ht
->bits
.mutations
= 1;
1714 if (0 == new_num_buckets
) {
1715 #if ENABLE_MEMORY_COUNTERS
1716 int64_t size_now
= OSAtomicAdd64Barrier((int64_t) CFBasicHashGetSize(ht
, true), & __CFBasicHashTotalSize
);
1717 while (__CFBasicHashPeakSize
< size_now
&& !OSAtomicCompareAndSwap64Barrier(__CFBasicHashPeakSize
, size_now
, & __CFBasicHashPeakSize
));
1718 int64_t count_now
= OSAtomicAdd64Barrier(1, & __CFBasicHashTotalCount
);
1719 while (__CFBasicHashPeakCount
< count_now
&& !OSAtomicCompareAndSwap64Barrier(__CFBasicHashPeakCount
, count_now
, & __CFBasicHashPeakCount
));
1720 OSAtomicAdd32Barrier(1, &__CFBasicHashSizes
[ht
->bits
.num_buckets_idx
]);
1725 CFBasicHashValue
*old_values
= NULL
, *old_keys
= NULL
;
1726 void *old_counts
= NULL
;
1727 uintptr_t *old_hashes
= NULL
;
1729 old_values
= __CFBasicHashGetValues(src_ht
);
1730 if (src_ht
->bits
.keys_offset
) {
1731 old_keys
= __CFBasicHashGetKeys(src_ht
);
1733 if (src_ht
->bits
.counts_offset
) {
1734 old_counts
= __CFBasicHashGetCounts(src_ht
);
1736 if (__CFBasicHashHasHashCache(src_ht
)) {
1737 old_hashes
= __CFBasicHashGetHashes(src_ht
);
1740 __CFBasicHashSetValues(ht
, new_values
);
1742 __CFBasicHashSetKeys(ht
, new_keys
);
1745 __CFBasicHashSetCounts(ht
, new_counts
);
1748 __CFBasicHashSetHashes(ht
, new_hashes
);
1751 for (CFIndex idx
= 0; idx
< new_num_buckets
; idx
++) {
1752 uintptr_t stack_value
= old_values
[idx
].neutral
;
1753 if (stack_value
!= 0UL && stack_value
!= ~0UL) {
1754 uintptr_t old_value
= stack_value
;
1755 if (__CFBasicHashSubABZero
== old_value
) old_value
= 0UL;
1756 if (__CFBasicHashSubABOne
== old_value
) old_value
= ~0UL;
1757 __CFBasicHashSetValue(ht
, idx
, __CFBasicHashImportValue(ht
, old_value
), true, false);
1759 uintptr_t old_key
= old_keys
[idx
].neutral
;
1760 if (__CFBasicHashSubABZero
== old_key
) old_key
= 0UL;
1761 if (__CFBasicHashSubABOne
== old_key
) old_key
= ~0UL;
1762 __CFBasicHashSetKey(ht
, idx
, __CFBasicHashImportKey(ht
, old_key
), true, false);
1765 __CFBasicHashSetValue(ht
, idx
, stack_value
, true, true);
1767 __CFBasicHashSetKey(ht
, idx
, stack_value
, true, true);
1771 if (new_counts
) memmove(new_counts
, old_counts
, new_num_buckets
* (1 << ht
->bits
.counts_width
));
1772 if (new_hashes
) memmove(new_hashes
, old_hashes
, new_num_buckets
* sizeof(uintptr_t));
1774 #if ENABLE_MEMORY_COUNTERS
1775 int64_t size_now
= OSAtomicAdd64Barrier((int64_t) CFBasicHashGetSize(ht
, true), & __CFBasicHashTotalSize
);
1776 while (__CFBasicHashPeakSize
< size_now
&& !OSAtomicCompareAndSwap64Barrier(__CFBasicHashPeakSize
, size_now
, & __CFBasicHashPeakSize
));
1777 int64_t count_now
= OSAtomicAdd64Barrier(1, & __CFBasicHashTotalCount
);
1778 while (__CFBasicHashPeakCount
< count_now
&& !OSAtomicCompareAndSwap64Barrier(__CFBasicHashPeakCount
, count_now
, & __CFBasicHashPeakCount
));
1779 OSAtomicAdd32Barrier(1, &__CFBasicHashSizes
[ht
->bits
.num_buckets_idx
]);