2 * Copyright (c) 2015 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-2014, 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
__CFBasicHashHasHashCache(CFConstBasicHashRef ht
) {
395 #if DEPLOYMENT_TARGET_MACOSX
396 return ht
->bits
.hashes_offset
? true : false;
402 CF_INLINE
uintptr_t __CFBasicHashImportValue(CFConstBasicHashRef ht
, uintptr_t stack_value
) {
403 uintptr_t (*func
)(CFAllocatorRef
, uintptr_t) = (uintptr_t (*)(CFAllocatorRef
, uintptr_t))CFBasicHashCallBackPtrs
[ht
->bits
.__vret
];
404 if (!func
|| ht
->bits
.null_rc
) return stack_value
;
405 CFAllocatorRef alloc
= CFGetAllocator(ht
);
406 return func(alloc
, stack_value
);
409 CF_INLINE
uintptr_t __CFBasicHashImportKey(CFConstBasicHashRef ht
, uintptr_t stack_key
) {
410 uintptr_t (*func
)(CFAllocatorRef
, uintptr_t) = (uintptr_t (*)(CFAllocatorRef
, uintptr_t))CFBasicHashCallBackPtrs
[ht
->bits
.__kret
];
411 if (!func
|| ht
->bits
.null_rc
) return stack_key
;
412 CFAllocatorRef alloc
= CFGetAllocator(ht
);
413 return func(alloc
, stack_key
);
416 CF_INLINE
void __CFBasicHashEjectValue(CFConstBasicHashRef ht
, uintptr_t stack_value
) {
417 void (*func
)(CFAllocatorRef
, uintptr_t) = (void (*)(CFAllocatorRef
, uintptr_t))CFBasicHashCallBackPtrs
[ht
->bits
.__vrel
];
418 if (!func
|| ht
->bits
.null_rc
) return;
419 CFAllocatorRef alloc
= CFGetAllocator(ht
);
420 func(alloc
, stack_value
);
423 CF_INLINE
void __CFBasicHashEjectKey(CFConstBasicHashRef ht
, uintptr_t stack_key
) {
424 void (*func
)(CFAllocatorRef
, uintptr_t) = (void (*)(CFAllocatorRef
, uintptr_t))CFBasicHashCallBackPtrs
[ht
->bits
.__krel
];
425 if (!func
|| ht
->bits
.null_rc
) return;
426 CFAllocatorRef alloc
= CFGetAllocator(ht
);
427 func(alloc
, stack_key
);
430 CF_INLINE CFStringRef
__CFBasicHashDescValue(CFConstBasicHashRef ht
, uintptr_t stack_value
) {
431 CFStringRef (*func
)(uintptr_t) = (CFStringRef (*)(uintptr_t))CFBasicHashCallBackPtrs
[ht
->bits
.__vdes
];
432 if (!func
) return CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("<%p>"), (void *)stack_value
);
433 return func(stack_value
);
436 CF_INLINE CFStringRef
__CFBasicHashDescKey(CFConstBasicHashRef ht
, uintptr_t stack_key
) {
437 CFStringRef (*func
)(uintptr_t) = (CFStringRef (*)(uintptr_t))CFBasicHashCallBackPtrs
[ht
->bits
.__kdes
];
438 if (!func
) return CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("<%p>"), (void *)stack_key
);
439 return func(stack_key
);
442 CF_INLINE Boolean
__CFBasicHashTestEqualValue(CFConstBasicHashRef ht
, uintptr_t stack_value_a
, uintptr_t stack_value_b
) {
443 Boolean (*func
)(uintptr_t, uintptr_t) = (Boolean (*)(uintptr_t, uintptr_t))CFBasicHashCallBackPtrs
[ht
->bits
.__vequ
];
444 if (!func
) return (stack_value_a
== stack_value_b
);
445 return func(stack_value_a
, stack_value_b
);
448 CF_INLINE Boolean
__CFBasicHashTestEqualKey(CFConstBasicHashRef ht
, uintptr_t in_coll_key
, uintptr_t stack_key
) {
449 COCOA_HASHTABLE_TEST_EQUAL(ht
, in_coll_key
, stack_key
);
450 Boolean (*func
)(uintptr_t, uintptr_t) = (Boolean (*)(uintptr_t, uintptr_t))CFBasicHashCallBackPtrs
[ht
->bits
.__kequ
];
451 if (!func
) return (in_coll_key
== stack_key
);
452 return func(in_coll_key
, stack_key
);
455 CF_INLINE CFHashCode
__CFBasicHashHashKey(CFConstBasicHashRef ht
, uintptr_t stack_key
) {
456 CFHashCode (*func
)(uintptr_t) = (CFHashCode (*)(uintptr_t))CFBasicHashCallBackPtrs
[ht
->bits
.__khas
];
457 CFHashCode hash_code
= func
? func(stack_key
) : stack_key
;
458 COCOA_HASHTABLE_HASH_KEY(ht
, stack_key
, hash_code
);
462 CF_INLINE
uintptr_t __CFBasicHashGetIndirectKey(CFConstBasicHashRef ht
, uintptr_t coll_key
) {
463 uintptr_t (*func
)(uintptr_t) = (uintptr_t (*)(uintptr_t))CFBasicHashCallBackPtrs
[ht
->bits
.__kget
];
464 if (!func
) return coll_key
;
465 return func(coll_key
);
468 CF_INLINE CFBasicHashValue
*__CFBasicHashGetValues(CFConstBasicHashRef ht
) {
469 return (CFBasicHashValue
*)ht
->pointers
[0];
472 CF_INLINE
void __CFBasicHashSetValues(CFBasicHashRef ht
, CFBasicHashValue
*ptr
) {
473 __AssignWithWriteBarrier(&ht
->pointers
[0], ptr
);
476 CF_INLINE CFBasicHashValue
*__CFBasicHashGetKeys(CFConstBasicHashRef ht
) {
477 return (CFBasicHashValue
*)ht
->pointers
[ht
->bits
.keys_offset
];
480 CF_INLINE
void __CFBasicHashSetKeys(CFBasicHashRef ht
, CFBasicHashValue
*ptr
) {
481 __AssignWithWriteBarrier(&ht
->pointers
[ht
->bits
.keys_offset
], ptr
);
484 CF_INLINE
void *__CFBasicHashGetCounts(CFConstBasicHashRef ht
) {
485 return (void *)ht
->pointers
[ht
->bits
.counts_offset
];
488 CF_INLINE
void __CFBasicHashSetCounts(CFBasicHashRef ht
, void *ptr
) {
489 __AssignWithWriteBarrier(&ht
->pointers
[ht
->bits
.counts_offset
], ptr
);
492 CF_INLINE
uintptr_t __CFBasicHashGetValue(CFConstBasicHashRef ht
, CFIndex idx
) {
493 uintptr_t val
= __CFBasicHashGetValues(ht
)[idx
].neutral
;
494 if (__CFBasicHashSubABZero
== val
) return 0UL;
495 if (__CFBasicHashSubABOne
== val
) return ~0UL;
499 CF_INLINE
void __CFBasicHashSetValue(CFBasicHashRef ht
, CFIndex idx
, uintptr_t stack_value
, Boolean ignoreOld
, Boolean literal
) {
500 CFBasicHashValue
*valuep
= &(__CFBasicHashGetValues(ht
)[idx
]);
501 uintptr_t old_value
= ignoreOld
? 0 : valuep
->neutral
;
503 if (0UL == stack_value
) stack_value
= __CFBasicHashSubABZero
;
504 if (~0UL == stack_value
) stack_value
= __CFBasicHashSubABOne
;
506 if (CFBasicHashHasStrongValues(ht
)) valuep
->strong
= (id
)stack_value
; else valuep
->neutral
= stack_value
;
508 if (!(old_value
== 0UL || old_value
== ~0UL)) {
509 if (__CFBasicHashSubABZero
== old_value
) old_value
= 0UL;
510 if (__CFBasicHashSubABOne
== old_value
) old_value
= ~0UL;
511 __CFBasicHashEjectValue(ht
, old_value
);
516 CF_INLINE
uintptr_t __CFBasicHashGetKey(CFConstBasicHashRef ht
, CFIndex idx
) {
517 if (ht
->bits
.keys_offset
) {
518 uintptr_t key
= __CFBasicHashGetKeys(ht
)[idx
].neutral
;
519 if (__CFBasicHashSubABZero
== key
) return 0UL;
520 if (__CFBasicHashSubABOne
== key
) return ~0UL;
523 if (ht
->bits
.indirect_keys
) {
524 uintptr_t stack_value
= __CFBasicHashGetValue(ht
, idx
);
525 return __CFBasicHashGetIndirectKey(ht
, stack_value
);
527 return __CFBasicHashGetValue(ht
, idx
);
530 CF_INLINE
void __CFBasicHashSetKey(CFBasicHashRef ht
, CFIndex idx
, uintptr_t stack_key
, Boolean ignoreOld
, Boolean literal
) {
531 if (0 == ht
->bits
.keys_offset
) HALT
;
532 CFBasicHashValue
*keyp
= &(__CFBasicHashGetKeys(ht
)[idx
]);
533 uintptr_t old_key
= ignoreOld
? 0 : keyp
->neutral
;
535 if (0UL == stack_key
) stack_key
= __CFBasicHashSubABZero
;
536 if (~0UL == stack_key
) stack_key
= __CFBasicHashSubABOne
;
538 if (CFBasicHashHasStrongKeys(ht
)) keyp
->strong
= (id
)stack_key
; else keyp
->neutral
= stack_key
;
540 if (!(old_key
== 0UL || old_key
== ~0UL)) {
541 if (__CFBasicHashSubABZero
== old_key
) old_key
= 0UL;
542 if (__CFBasicHashSubABOne
== old_key
) old_key
= ~0UL;
543 __CFBasicHashEjectKey(ht
, old_key
);
548 CF_INLINE
uintptr_t __CFBasicHashIsEmptyOrDeleted(CFConstBasicHashRef ht
, CFIndex idx
) {
549 uintptr_t stack_value
= __CFBasicHashGetValues(ht
)[idx
].neutral
;
550 return (0UL == stack_value
|| ~0UL == stack_value
);
553 CF_INLINE
uintptr_t __CFBasicHashIsDeleted(CFConstBasicHashRef ht
, CFIndex idx
) {
554 uintptr_t stack_value
= __CFBasicHashGetValues(ht
)[idx
].neutral
;
555 return (~0UL == stack_value
);
558 CF_INLINE
uintptr_t __CFBasicHashGetSlotCount(CFConstBasicHashRef ht
, CFIndex idx
) {
559 void *counts
= __CFBasicHashGetCounts(ht
);
560 switch (ht
->bits
.counts_width
) {
561 case 0: return ((uint8_t *)counts
)[idx
];
562 case 1: return ((uint16_t *)counts
)[idx
];
563 case 2: return ((uint32_t *)counts
)[idx
];
564 case 3: return ((uint64_t *)counts
)[idx
];
569 CF_INLINE
void __CFBasicHashBumpCounts(CFBasicHashRef ht
) {
570 void *counts
= __CFBasicHashGetCounts(ht
);
571 CFAllocatorRef allocator
= CFGetAllocator(ht
);
572 switch (ht
->bits
.counts_width
) {
574 uint8_t *counts08
= (uint8_t *)counts
;
575 ht
->bits
.counts_width
= 1;
576 CFIndex num_buckets
= __CFBasicHashTableSizes
[ht
->bits
.num_buckets_idx
];
577 uint16_t *counts16
= (uint16_t *)__CFBasicHashAllocateMemory(ht
, num_buckets
, 2, false, false);
579 __SetLastAllocationEventName(counts16
, "CFBasicHash (count-store)");
580 for (CFIndex idx2
= 0; idx2
< num_buckets
; idx2
++) {
581 counts16
[idx2
] = counts08
[idx2
];
583 __CFBasicHashSetCounts(ht
, counts16
);
584 if (!CF_IS_COLLECTABLE_ALLOCATOR(allocator
)) {
585 CFAllocatorDeallocate(allocator
, counts08
);
590 uint16_t *counts16
= (uint16_t *)counts
;
591 ht
->bits
.counts_width
= 2;
592 CFIndex num_buckets
= __CFBasicHashTableSizes
[ht
->bits
.num_buckets_idx
];
593 uint32_t *counts32
= (uint32_t *)__CFBasicHashAllocateMemory(ht
, num_buckets
, 4, false, false);
595 __SetLastAllocationEventName(counts32
, "CFBasicHash (count-store)");
596 for (CFIndex idx2
= 0; idx2
< num_buckets
; idx2
++) {
597 counts32
[idx2
] = counts16
[idx2
];
599 __CFBasicHashSetCounts(ht
, counts32
);
600 if (!CF_IS_COLLECTABLE_ALLOCATOR(allocator
)) {
601 CFAllocatorDeallocate(allocator
, counts16
);
606 uint32_t *counts32
= (uint32_t *)counts
;
607 ht
->bits
.counts_width
= 3;
608 CFIndex num_buckets
= __CFBasicHashTableSizes
[ht
->bits
.num_buckets_idx
];
609 uint64_t *counts64
= (uint64_t *)__CFBasicHashAllocateMemory(ht
, num_buckets
, 8, false, false);
611 __SetLastAllocationEventName(counts64
, "CFBasicHash (count-store)");
612 for (CFIndex idx2
= 0; idx2
< num_buckets
; idx2
++) {
613 counts64
[idx2
] = counts32
[idx2
];
615 __CFBasicHashSetCounts(ht
, counts64
);
616 if (!CF_IS_COLLECTABLE_ALLOCATOR(allocator
)) {
617 CFAllocatorDeallocate(allocator
, counts32
);
628 static void __CFBasicHashIncSlotCount(CFBasicHashRef ht
, CFIndex idx
) {
629 void *counts
= __CFBasicHashGetCounts(ht
);
630 switch (ht
->bits
.counts_width
) {
632 uint8_t *counts08
= (uint8_t *)counts
;
633 uint8_t val
= counts08
[idx
];
634 if (val
< INT8_MAX
) {
635 counts08
[idx
] = val
+ 1;
638 __CFBasicHashBumpCounts(ht
);
639 __CFBasicHashIncSlotCount(ht
, idx
);
643 uint16_t *counts16
= (uint16_t *)counts
;
644 uint16_t val
= counts16
[idx
];
645 if (val
< INT16_MAX
) {
646 counts16
[idx
] = val
+ 1;
649 __CFBasicHashBumpCounts(ht
);
650 __CFBasicHashIncSlotCount(ht
, idx
);
654 uint32_t *counts32
= (uint32_t *)counts
;
655 uint32_t val
= counts32
[idx
];
656 if (val
< INT32_MAX
) {
657 counts32
[idx
] = val
+ 1;
660 __CFBasicHashBumpCounts(ht
);
661 __CFBasicHashIncSlotCount(ht
, idx
);
665 uint64_t *counts64
= (uint64_t *)counts
;
666 uint64_t val
= counts64
[idx
];
667 if (val
< INT64_MAX
) {
668 counts64
[idx
] = val
+ 1;
671 __CFBasicHashBumpCounts(ht
);
672 __CFBasicHashIncSlotCount(ht
, idx
);
678 CF_INLINE
void __CFBasicHashDecSlotCount(CFBasicHashRef ht
, CFIndex idx
) {
679 void *counts
= __CFBasicHashGetCounts(ht
);
680 switch (ht
->bits
.counts_width
) {
681 case 0: ((uint8_t *)counts
)[idx
]--; return;
682 case 1: ((uint16_t *)counts
)[idx
]--; return;
683 case 2: ((uint32_t *)counts
)[idx
]--; return;
684 case 3: ((uint64_t *)counts
)[idx
]--; return;
688 CF_INLINE
uintptr_t *__CFBasicHashGetHashes(CFConstBasicHashRef ht
) {
689 return (uintptr_t *)ht
->pointers
[ht
->bits
.hashes_offset
];
692 CF_INLINE
void __CFBasicHashSetHashes(CFBasicHashRef ht
, uintptr_t *ptr
) {
693 __AssignWithWriteBarrier(&ht
->pointers
[ht
->bits
.hashes_offset
], ptr
);
697 // to expose the load factor, expose this function to customization
698 CF_INLINE CFIndex
__CFBasicHashGetCapacityForNumBuckets(CFConstBasicHashRef ht
, CFIndex num_buckets_idx
) {
699 return __CFBasicHashTableCapacities
[num_buckets_idx
];
702 CF_INLINE CFIndex
__CFBasicHashGetNumBucketsIndexForCapacity(CFConstBasicHashRef ht
, CFIndex capacity
) {
703 for (CFIndex idx
= 0; idx
< 64; idx
++) {
704 if (capacity
<= __CFBasicHashGetCapacityForNumBuckets(ht
, idx
)) return idx
;
710 CF_PRIVATE CFIndex
CFBasicHashGetNumBuckets(CFConstBasicHashRef ht
) {
711 return __CFBasicHashTableSizes
[ht
->bits
.num_buckets_idx
];
714 CF_PRIVATE CFIndex
CFBasicHashGetCapacity(CFConstBasicHashRef ht
) {
715 return __CFBasicHashGetCapacityForNumBuckets(ht
, ht
->bits
.num_buckets_idx
);
718 // In returned struct, .count is zero if the bucket is empty or deleted,
719 // and the .weak_key field indicates which. .idx is either the index of
720 // the found bucket or the index of the bucket which should be filled by
721 // an add operation. For a set or multiset, the .weak_key and .weak_value
723 CF_PRIVATE CFBasicHashBucket
CFBasicHashGetBucket(CFConstBasicHashRef ht
, CFIndex idx
) {
724 CFBasicHashBucket result
;
726 if (__CFBasicHashIsEmptyOrDeleted(ht
, idx
)) {
728 result
.weak_value
= 0;
731 result
.count
= (ht
->bits
.counts_offset
) ? __CFBasicHashGetSlotCount(ht
, idx
) : 1;
732 result
.weak_value
= __CFBasicHashGetValue(ht
, idx
);
733 result
.weak_key
= __CFBasicHashGetKey(ht
, idx
);
739 static uintptr_t __CFBasicHashFold(uintptr_t dividend
, uint8_t idx
) {
741 case 1: return dividend
% 3;
742 case 2: return dividend
% 7;
743 case 3: return dividend
% 13;
744 case 4: return dividend
% 23;
745 case 5: return dividend
% 41;
746 case 6: return dividend
% 71;
747 case 7: return dividend
% 127;
748 case 8: return dividend
% 191;
749 case 9: return dividend
% 251;
750 case 10: return dividend
% 383;
751 case 11: return dividend
% 631;
752 case 12: return dividend
% 1087;
753 case 13: return dividend
% 1723;
754 case 14: return dividend
% 2803;
755 case 15: return dividend
% 4523;
756 case 16: return dividend
% 7351;
757 case 17: return dividend
% 11959;
758 case 18: return dividend
% 19447;
759 case 19: return dividend
% 31231;
760 case 20: return dividend
% 50683;
761 case 21: return dividend
% 81919;
762 case 22: return dividend
% 132607;
763 case 23: return dividend
% 214519;
764 case 24: return dividend
% 346607;
765 case 25: return dividend
% 561109;
766 case 26: return dividend
% 907759;
767 case 27: return dividend
% 1468927;
768 case 28: return dividend
% 2376191;
769 case 29: return dividend
% 3845119;
770 case 30: return dividend
% 6221311;
771 case 31: return dividend
% 10066421;
772 case 32: return dividend
% 16287743;
773 case 33: return dividend
% 26354171;
774 case 34: return dividend
% 42641881;
775 case 35: return dividend
% 68996069;
776 case 36: return dividend
% 111638519;
777 case 37: return dividend
% 180634607;
778 case 38: return dividend
% 292272623;
779 case 39: return dividend
% 472907251;
787 #define FIND_BUCKET_NAME ___CFBasicHashFindBucket_Linear
788 #define FIND_BUCKET_HASH_STYLE 1
789 #define FIND_BUCKET_FOR_REHASH 0
790 #define FIND_BUCKET_FOR_INDIRECT_KEY 0
791 #include "CFBasicHashFindBucket.m"
793 #define FIND_BUCKET_NAME ___CFBasicHashFindBucket_Linear_NoCollision
794 #define FIND_BUCKET_HASH_STYLE 1
795 #define FIND_BUCKET_FOR_REHASH 1
796 #define FIND_BUCKET_FOR_INDIRECT_KEY 0
797 #include "CFBasicHashFindBucket.m"
799 #define FIND_BUCKET_NAME ___CFBasicHashFindBucket_Linear_Indirect
800 #define FIND_BUCKET_HASH_STYLE 1
801 #define FIND_BUCKET_FOR_REHASH 0
802 #define FIND_BUCKET_FOR_INDIRECT_KEY 1
803 #include "CFBasicHashFindBucket.m"
805 #define FIND_BUCKET_NAME ___CFBasicHashFindBucket_Linear_Indirect_NoCollision
806 #define FIND_BUCKET_HASH_STYLE 1
807 #define FIND_BUCKET_FOR_REHASH 1
808 #define FIND_BUCKET_FOR_INDIRECT_KEY 1
809 #include "CFBasicHashFindBucket.m"
811 #define FIND_BUCKET_NAME ___CFBasicHashFindBucket_Double
812 #define FIND_BUCKET_HASH_STYLE 2
813 #define FIND_BUCKET_FOR_REHASH 0
814 #define FIND_BUCKET_FOR_INDIRECT_KEY 0
815 #include "CFBasicHashFindBucket.m"
817 #define FIND_BUCKET_NAME ___CFBasicHashFindBucket_Double_NoCollision
818 #define FIND_BUCKET_HASH_STYLE 2
819 #define FIND_BUCKET_FOR_REHASH 1
820 #define FIND_BUCKET_FOR_INDIRECT_KEY 0
821 #include "CFBasicHashFindBucket.m"
823 #define FIND_BUCKET_NAME ___CFBasicHashFindBucket_Double_Indirect
824 #define FIND_BUCKET_HASH_STYLE 2
825 #define FIND_BUCKET_FOR_REHASH 0
826 #define FIND_BUCKET_FOR_INDIRECT_KEY 1
827 #include "CFBasicHashFindBucket.m"
829 #define FIND_BUCKET_NAME ___CFBasicHashFindBucket_Double_Indirect_NoCollision
830 #define FIND_BUCKET_HASH_STYLE 2
831 #define FIND_BUCKET_FOR_REHASH 1
832 #define FIND_BUCKET_FOR_INDIRECT_KEY 1
833 #include "CFBasicHashFindBucket.m"
835 #define FIND_BUCKET_NAME ___CFBasicHashFindBucket_Exponential
836 #define FIND_BUCKET_HASH_STYLE 3
837 #define FIND_BUCKET_FOR_REHASH 0
838 #define FIND_BUCKET_FOR_INDIRECT_KEY 0
839 #include "CFBasicHashFindBucket.m"
841 #define FIND_BUCKET_NAME ___CFBasicHashFindBucket_Exponential_NoCollision
842 #define FIND_BUCKET_HASH_STYLE 3
843 #define FIND_BUCKET_FOR_REHASH 1
844 #define FIND_BUCKET_FOR_INDIRECT_KEY 0
845 #include "CFBasicHashFindBucket.m"
847 #define FIND_BUCKET_NAME ___CFBasicHashFindBucket_Exponential_Indirect
848 #define FIND_BUCKET_HASH_STYLE 3
849 #define FIND_BUCKET_FOR_REHASH 0
850 #define FIND_BUCKET_FOR_INDIRECT_KEY 1
851 #include "CFBasicHashFindBucket.m"
853 #define FIND_BUCKET_NAME ___CFBasicHashFindBucket_Exponential_Indirect_NoCollision
854 #define FIND_BUCKET_HASH_STYLE 3
855 #define FIND_BUCKET_FOR_REHASH 1
856 #define FIND_BUCKET_FOR_INDIRECT_KEY 1
857 #include "CFBasicHashFindBucket.m"
860 CF_INLINE CFBasicHashBucket
__CFBasicHashFindBucket(CFConstBasicHashRef ht
, uintptr_t stack_key
) {
861 if (0 == ht
->bits
.num_buckets_idx
) {
862 CFBasicHashBucket result
= {kCFNotFound
, 0UL, 0UL, 0};
865 if (ht
->bits
.indirect_keys
) {
866 switch (ht
->bits
.hash_style
) {
867 case __kCFBasicHashLinearHashingValue
: return ___CFBasicHashFindBucket_Linear_Indirect(ht
, stack_key
);
868 case __kCFBasicHashDoubleHashingValue
: return ___CFBasicHashFindBucket_Double_Indirect(ht
, stack_key
);
869 case __kCFBasicHashExponentialHashingValue
: return ___CFBasicHashFindBucket_Exponential_Indirect(ht
, stack_key
);
872 switch (ht
->bits
.hash_style
) {
873 case __kCFBasicHashLinearHashingValue
: return ___CFBasicHashFindBucket_Linear(ht
, stack_key
);
874 case __kCFBasicHashDoubleHashingValue
: return ___CFBasicHashFindBucket_Double(ht
, stack_key
);
875 case __kCFBasicHashExponentialHashingValue
: return ___CFBasicHashFindBucket_Exponential(ht
, stack_key
);
879 CFBasicHashBucket result
= {kCFNotFound
, 0UL, 0UL, 0};
883 CF_INLINE CFIndex
__CFBasicHashFindBucket_NoCollision(CFConstBasicHashRef ht
, uintptr_t stack_key
, uintptr_t key_hash
) {
884 if (0 == ht
->bits
.num_buckets_idx
) {
887 if (ht
->bits
.indirect_keys
) {
888 switch (ht
->bits
.hash_style
) {
889 case __kCFBasicHashLinearHashingValue
: return ___CFBasicHashFindBucket_Linear_Indirect_NoCollision(ht
, stack_key
, key_hash
);
890 case __kCFBasicHashDoubleHashingValue
: return ___CFBasicHashFindBucket_Double_Indirect_NoCollision(ht
, stack_key
, key_hash
);
891 case __kCFBasicHashExponentialHashingValue
: return ___CFBasicHashFindBucket_Exponential_Indirect_NoCollision(ht
, stack_key
, key_hash
);
894 switch (ht
->bits
.hash_style
) {
895 case __kCFBasicHashLinearHashingValue
: return ___CFBasicHashFindBucket_Linear_NoCollision(ht
, stack_key
, key_hash
);
896 case __kCFBasicHashDoubleHashingValue
: return ___CFBasicHashFindBucket_Double_NoCollision(ht
, stack_key
, key_hash
);
897 case __kCFBasicHashExponentialHashingValue
: return ___CFBasicHashFindBucket_Exponential_NoCollision(ht
, stack_key
, key_hash
);
904 CF_PRIVATE CFBasicHashBucket
CFBasicHashFindBucket(CFConstBasicHashRef ht
, uintptr_t stack_key
) {
905 if (__CFBasicHashSubABZero
== stack_key
|| __CFBasicHashSubABOne
== stack_key
) {
906 CFBasicHashBucket result
= {kCFNotFound
, 0UL, 0UL, 0};
909 return __CFBasicHashFindBucket(ht
, stack_key
);
912 CF_PRIVATE
void CFBasicHashSuppressRC(CFBasicHashRef ht
) {
913 ht
->bits
.null_rc
= 1;
916 CF_PRIVATE
void CFBasicHashUnsuppressRC(CFBasicHashRef ht
) {
917 ht
->bits
.null_rc
= 0;
920 CF_PRIVATE CFOptionFlags
CFBasicHashGetFlags(CFConstBasicHashRef ht
) {
921 CFOptionFlags flags
= (ht
->bits
.hash_style
<< 13);
922 if (CFBasicHashHasStrongValues(ht
)) flags
|= kCFBasicHashStrongValues
;
923 if (CFBasicHashHasStrongKeys(ht
)) flags
|= kCFBasicHashStrongKeys
;
924 if (ht
->bits
.fast_grow
) flags
|= kCFBasicHashAggressiveGrowth
;
925 if (ht
->bits
.keys_offset
) flags
|= kCFBasicHashHasKeys
;
926 if (ht
->bits
.counts_offset
) flags
|= kCFBasicHashHasCounts
;
927 if (__CFBasicHashHasHashCache(ht
)) flags
|= kCFBasicHashHasHashCache
;
931 CF_PRIVATE CFIndex
CFBasicHashGetCount(CFConstBasicHashRef ht
) {
932 if (ht
->bits
.counts_offset
) {
934 CFIndex cnt
= (CFIndex
)__CFBasicHashTableSizes
[ht
->bits
.num_buckets_idx
];
935 for (CFIndex idx
= 0; idx
< cnt
; idx
++) {
936 total
+= __CFBasicHashGetSlotCount(ht
, idx
);
940 return (CFIndex
)ht
->bits
.used_buckets
;
943 CF_PRIVATE CFIndex
CFBasicHashGetCountOfKey(CFConstBasicHashRef ht
, uintptr_t stack_key
) {
944 if (__CFBasicHashSubABZero
== stack_key
|| __CFBasicHashSubABOne
== stack_key
) {
947 if (0L == ht
->bits
.used_buckets
) {
950 return __CFBasicHashFindBucket(ht
, stack_key
).count
;
953 CF_PRIVATE CFIndex
CFBasicHashGetCountOfValue(CFConstBasicHashRef ht
, uintptr_t stack_value
) {
954 if (__CFBasicHashSubABZero
== stack_value
) {
957 if (0L == ht
->bits
.used_buckets
) {
960 if (!(ht
->bits
.keys_offset
)) {
961 return __CFBasicHashFindBucket(ht
, stack_value
).count
;
963 __block CFIndex total
= 0L;
964 CFBasicHashApply(ht
, ^(CFBasicHashBucket bkt
) {
965 if ((stack_value
== bkt
.weak_value
) || __CFBasicHashTestEqualValue(ht
, bkt
.weak_value
, stack_value
)) total
+= bkt
.count
;
966 return (Boolean
)true;
971 CF_PRIVATE Boolean
CFBasicHashesAreEqual(CFConstBasicHashRef ht1
, CFConstBasicHashRef ht2
) {
972 CFIndex cnt1
= CFBasicHashGetCount(ht1
);
973 if (cnt1
!= CFBasicHashGetCount(ht2
)) return false;
974 if (0 == cnt1
) return true;
975 __block Boolean equal
= true;
976 CFBasicHashApply(ht1
, ^(CFBasicHashBucket bkt1
) {
977 CFBasicHashBucket bkt2
= __CFBasicHashFindBucket(ht2
, bkt1
.weak_key
);
978 if (bkt1
.count
!= bkt2
.count
) {
980 return (Boolean
)false;
982 if ((ht1
->bits
.keys_offset
) && (bkt1
.weak_value
!= bkt2
.weak_value
) && !__CFBasicHashTestEqualValue(ht1
, bkt1
.weak_value
, bkt2
.weak_value
)) {
984 return (Boolean
)false;
986 return (Boolean
)true;
991 CF_PRIVATE
void CFBasicHashApply(CFConstBasicHashRef ht
, Boolean (^block
)(CFBasicHashBucket
)) {
992 CFIndex used
= (CFIndex
)ht
->bits
.used_buckets
, cnt
= (CFIndex
)__CFBasicHashTableSizes
[ht
->bits
.num_buckets_idx
];
993 for (CFIndex idx
= 0; 0 < used
&& idx
< cnt
; idx
++) {
994 CFBasicHashBucket bkt
= CFBasicHashGetBucket(ht
, idx
);
1004 CF_PRIVATE
void CFBasicHashApplyIndexed(CFConstBasicHashRef ht
, CFRange range
, Boolean (^block
)(CFBasicHashBucket
)) {
1005 if (range
.length
< 0) HALT
;
1006 if (range
.length
== 0) return;
1007 CFIndex cnt
= (CFIndex
)__CFBasicHashTableSizes
[ht
->bits
.num_buckets_idx
];
1008 if (cnt
< range
.location
+ range
.length
) HALT
;
1009 for (CFIndex idx
= 0; idx
< range
.length
; idx
++) {
1010 CFBasicHashBucket bkt
= CFBasicHashGetBucket(ht
, range
.location
+ idx
);
1011 if (0 < bkt
.count
) {
1019 CF_PRIVATE
void CFBasicHashGetElements(CFConstBasicHashRef ht
, CFIndex bufferslen
, uintptr_t *weak_values
, uintptr_t *weak_keys
) {
1020 CFIndex used
= (CFIndex
)ht
->bits
.used_buckets
, cnt
= (CFIndex
)__CFBasicHashTableSizes
[ht
->bits
.num_buckets_idx
];
1022 for (CFIndex idx
= 0; 0 < used
&& idx
< cnt
&& offset
< bufferslen
; idx
++) {
1023 CFBasicHashBucket bkt
= CFBasicHashGetBucket(ht
, idx
);
1024 if (0 < bkt
.count
) {
1026 for (CFIndex cnt
= bkt
.count
; cnt
-- && offset
< bufferslen
;) {
1027 if (weak_values
) { weak_values
[offset
] = bkt
.weak_value
; }
1028 if (weak_keys
) { weak_keys
[offset
] = bkt
.weak_key
; }
1035 CF_PRIVATE
unsigned long __CFBasicHashFastEnumeration(CFConstBasicHashRef ht
, struct __objcFastEnumerationStateEquivalent2
*state
, void *stackbuffer
, unsigned long count
) {
1036 /* copy as many as count items over */
1037 if (0 == state
->state
) { /* first time */
1038 state
->mutationsPtr
= (unsigned long *)&ht
->bits
;
1040 state
->itemsPtr
= (unsigned long *)stackbuffer
;
1042 CFIndex used
= (CFIndex
)ht
->bits
.used_buckets
, cnt
= (CFIndex
)__CFBasicHashTableSizes
[ht
->bits
.num_buckets_idx
];
1043 for (CFIndex idx
= (CFIndex
)state
->state
; 0 < used
&& idx
< cnt
&& cntx
< (CFIndex
)count
; idx
++) {
1044 CFBasicHashBucket bkt
= CFBasicHashGetBucket(ht
, idx
);
1045 if (0 < bkt
.count
) {
1046 state
->itemsPtr
[cntx
++] = (unsigned long)bkt
.weak_key
;
1054 #if ENABLE_MEMORY_COUNTERS
1055 static volatile int64_t __CFBasicHashTotalCount
= 0ULL;
1056 static volatile int64_t __CFBasicHashTotalSize
= 0ULL;
1057 static volatile int64_t __CFBasicHashPeakCount
= 0ULL;
1058 static volatile int64_t __CFBasicHashPeakSize
= 0ULL;
1059 static volatile int32_t __CFBasicHashSizes
[64] = {0};
1062 static void __CFBasicHashDrain(CFBasicHashRef ht
, Boolean forFinalization
) {
1063 #if ENABLE_MEMORY_COUNTERS
1064 OSAtomicAdd64Barrier(-1 * (int64_t) CFBasicHashGetSize(ht
, true), & __CFBasicHashTotalSize
);
1067 CFIndex old_num_buckets
= __CFBasicHashTableSizes
[ht
->bits
.num_buckets_idx
];
1069 CFAllocatorRef allocator
= CFGetAllocator(ht
);
1070 Boolean nullify
= (!forFinalization
|| !CF_IS_COLLECTABLE_ALLOCATOR(allocator
));
1072 CFBasicHashValue
*old_values
= NULL
, *old_keys
= NULL
;
1073 void *old_counts
= NULL
;
1074 uintptr_t *old_hashes
= NULL
;
1076 old_values
= __CFBasicHashGetValues(ht
);
1077 if (nullify
) __CFBasicHashSetValues(ht
, NULL
);
1078 if (ht
->bits
.keys_offset
) {
1079 old_keys
= __CFBasicHashGetKeys(ht
);
1080 if (nullify
) __CFBasicHashSetKeys(ht
, NULL
);
1082 if (ht
->bits
.counts_offset
) {
1083 old_counts
= __CFBasicHashGetCounts(ht
);
1084 if (nullify
) __CFBasicHashSetCounts(ht
, NULL
);
1086 if (__CFBasicHashHasHashCache(ht
)) {
1087 old_hashes
= __CFBasicHashGetHashes(ht
);
1088 if (nullify
) __CFBasicHashSetHashes(ht
, NULL
);
1092 ht
->bits
.mutations
++;
1093 ht
->bits
.num_buckets_idx
= 0;
1094 ht
->bits
.used_buckets
= 0;
1095 ht
->bits
.deleted
= 0;
1098 for (CFIndex idx
= 0; idx
< old_num_buckets
; idx
++) {
1099 uintptr_t stack_value
= old_values
[idx
].neutral
;
1100 if (stack_value
!= 0UL && stack_value
!= ~0UL) {
1101 uintptr_t old_value
= stack_value
;
1102 if (__CFBasicHashSubABZero
== old_value
) old_value
= 0UL;
1103 if (__CFBasicHashSubABOne
== old_value
) old_value
= ~0UL;
1104 __CFBasicHashEjectValue(ht
, old_value
);
1106 uintptr_t old_key
= old_keys
[idx
].neutral
;
1107 if (__CFBasicHashSubABZero
== old_key
) old_key
= 0UL;
1108 if (__CFBasicHashSubABOne
== old_key
) old_key
= ~0UL;
1109 __CFBasicHashEjectKey(ht
, old_key
);
1114 if (!CF_IS_COLLECTABLE_ALLOCATOR(allocator
)) {
1115 CFAllocatorDeallocate(allocator
, old_values
);
1116 CFAllocatorDeallocate(allocator
, old_keys
);
1117 CFAllocatorDeallocate(allocator
, old_counts
);
1118 CFAllocatorDeallocate(allocator
, old_hashes
);
1121 #if ENABLE_MEMORY_COUNTERS
1122 int64_t size_now
= OSAtomicAdd64Barrier((int64_t) CFBasicHashGetSize(ht
, true), & __CFBasicHashTotalSize
);
1123 while (__CFBasicHashPeakSize
< size_now
&& !OSAtomicCompareAndSwap64Barrier(__CFBasicHashPeakSize
, size_now
, & __CFBasicHashPeakSize
));
1127 static void __CFBasicHashRehash(CFBasicHashRef ht
, CFIndex newItemCount
) {
1128 #if ENABLE_MEMORY_COUNTERS
1129 OSAtomicAdd64Barrier(-1 * (int64_t) CFBasicHashGetSize(ht
, true), & __CFBasicHashTotalSize
);
1130 OSAtomicAdd32Barrier(-1, &__CFBasicHashSizes
[ht
->bits
.num_buckets_idx
]);
1133 if (COCOA_HASHTABLE_REHASH_START_ENABLED()) COCOA_HASHTABLE_REHASH_START(ht
, CFBasicHashGetNumBuckets(ht
), CFBasicHashGetSize(ht
, true));
1135 CFIndex new_num_buckets_idx
= ht
->bits
.num_buckets_idx
;
1136 if (0 != newItemCount
) {
1137 if (newItemCount
< 0) newItemCount
= 0;
1138 CFIndex new_capacity_req
= ht
->bits
.used_buckets
+ newItemCount
;
1139 new_num_buckets_idx
= __CFBasicHashGetNumBucketsIndexForCapacity(ht
, new_capacity_req
);
1140 if (1 == newItemCount
&& ht
->bits
.fast_grow
) {
1141 new_num_buckets_idx
++;
1145 CFIndex new_num_buckets
= __CFBasicHashTableSizes
[new_num_buckets_idx
];
1146 CFIndex old_num_buckets
= __CFBasicHashTableSizes
[ht
->bits
.num_buckets_idx
];
1148 CFBasicHashValue
*new_values
= NULL
, *new_keys
= NULL
;
1149 void *new_counts
= NULL
;
1150 uintptr_t *new_hashes
= NULL
;
1152 if (0 < new_num_buckets
) {
1153 new_values
= (CFBasicHashValue
*)__CFBasicHashAllocateMemory(ht
, new_num_buckets
, sizeof(CFBasicHashValue
), CFBasicHashHasStrongValues(ht
), 0);
1154 if (!new_values
) HALT
;
1155 __SetLastAllocationEventName(new_values
, "CFBasicHash (value-store)");
1156 memset(new_values
, 0, new_num_buckets
* sizeof(CFBasicHashValue
));
1157 if (ht
->bits
.keys_offset
) {
1158 new_keys
= (CFBasicHashValue
*)__CFBasicHashAllocateMemory(ht
, new_num_buckets
, sizeof(CFBasicHashValue
), CFBasicHashHasStrongKeys(ht
), 0);
1159 if (!new_keys
) HALT
;
1160 __SetLastAllocationEventName(new_keys
, "CFBasicHash (key-store)");
1161 memset(new_keys
, 0, new_num_buckets
* sizeof(CFBasicHashValue
));
1163 if (ht
->bits
.counts_offset
) {
1164 new_counts
= (uintptr_t *)__CFBasicHashAllocateMemory(ht
, new_num_buckets
, (1 << ht
->bits
.counts_width
), false, false);
1165 if (!new_counts
) HALT
;
1166 __SetLastAllocationEventName(new_counts
, "CFBasicHash (count-store)");
1167 memset(new_counts
, 0, new_num_buckets
* (1 << ht
->bits
.counts_width
));
1169 if (__CFBasicHashHasHashCache(ht
)) {
1170 new_hashes
= (uintptr_t *)__CFBasicHashAllocateMemory(ht
, new_num_buckets
, sizeof(uintptr_t), false, false);
1171 if (!new_hashes
) HALT
;
1172 __SetLastAllocationEventName(new_hashes
, "CFBasicHash (hash-store)");
1173 memset(new_hashes
, 0, new_num_buckets
* sizeof(uintptr_t));
1177 ht
->bits
.num_buckets_idx
= new_num_buckets_idx
;
1178 ht
->bits
.deleted
= 0;
1180 CFBasicHashValue
*old_values
= NULL
, *old_keys
= NULL
;
1181 void *old_counts
= NULL
;
1182 uintptr_t *old_hashes
= NULL
;
1184 old_values
= __CFBasicHashGetValues(ht
);
1185 __CFBasicHashSetValues(ht
, new_values
);
1186 if (ht
->bits
.keys_offset
) {
1187 old_keys
= __CFBasicHashGetKeys(ht
);
1188 __CFBasicHashSetKeys(ht
, new_keys
);
1190 if (ht
->bits
.counts_offset
) {
1191 old_counts
= __CFBasicHashGetCounts(ht
);
1192 __CFBasicHashSetCounts(ht
, new_counts
);
1194 if (__CFBasicHashHasHashCache(ht
)) {
1195 old_hashes
= __CFBasicHashGetHashes(ht
);
1196 __CFBasicHashSetHashes(ht
, new_hashes
);
1199 if (0 < old_num_buckets
) {
1200 for (CFIndex idx
= 0; idx
< old_num_buckets
; idx
++) {
1201 uintptr_t stack_value
= old_values
[idx
].neutral
;
1202 if (stack_value
!= 0UL && stack_value
!= ~0UL) {
1203 if (__CFBasicHashSubABZero
== stack_value
) stack_value
= 0UL;
1204 if (__CFBasicHashSubABOne
== stack_value
) stack_value
= ~0UL;
1205 uintptr_t stack_key
= stack_value
;
1206 if (ht
->bits
.keys_offset
) {
1207 stack_key
= old_keys
[idx
].neutral
;
1208 if (__CFBasicHashSubABZero
== stack_key
) stack_key
= 0UL;
1209 if (__CFBasicHashSubABOne
== stack_key
) stack_key
= ~0UL;
1211 if (ht
->bits
.indirect_keys
) {
1212 stack_key
= __CFBasicHashGetIndirectKey(ht
, stack_value
);
1214 CFIndex bkt_idx
= __CFBasicHashFindBucket_NoCollision(ht
, stack_key
, old_hashes
? old_hashes
[idx
] : 0UL);
1215 __CFBasicHashSetValue(ht
, bkt_idx
, stack_value
, false, false);
1217 __CFBasicHashSetKey(ht
, bkt_idx
, stack_key
, false, false);
1220 switch (ht
->bits
.counts_width
) {
1221 case 0: ((uint8_t *)new_counts
)[bkt_idx
] = ((uint8_t *)old_counts
)[idx
]; break;
1222 case 1: ((uint16_t *)new_counts
)[bkt_idx
] = ((uint16_t *)old_counts
)[idx
]; break;
1223 case 2: ((uint32_t *)new_counts
)[bkt_idx
] = ((uint32_t *)old_counts
)[idx
]; break;
1224 case 3: ((uint64_t *)new_counts
)[bkt_idx
] = ((uint64_t *)old_counts
)[idx
]; break;
1228 new_hashes
[bkt_idx
] = old_hashes
[idx
];
1234 CFAllocatorRef allocator
= CFGetAllocator(ht
);
1235 if (!CF_IS_COLLECTABLE_ALLOCATOR(allocator
)) {
1236 CFAllocatorDeallocate(allocator
, old_values
);
1237 CFAllocatorDeallocate(allocator
, old_keys
);
1238 CFAllocatorDeallocate(allocator
, old_counts
);
1239 CFAllocatorDeallocate(allocator
, old_hashes
);
1242 if (COCOA_HASHTABLE_REHASH_END_ENABLED()) COCOA_HASHTABLE_REHASH_END(ht
, CFBasicHashGetNumBuckets(ht
), CFBasicHashGetSize(ht
, true));
1244 #if ENABLE_MEMORY_COUNTERS
1245 int64_t size_now
= OSAtomicAdd64Barrier((int64_t) CFBasicHashGetSize(ht
, true), &__CFBasicHashTotalSize
);
1246 while (__CFBasicHashPeakSize
< size_now
&& !OSAtomicCompareAndSwap64Barrier(__CFBasicHashPeakSize
, size_now
, & __CFBasicHashPeakSize
));
1247 OSAtomicAdd32Barrier(1, &__CFBasicHashSizes
[ht
->bits
.num_buckets_idx
]);
1251 CF_PRIVATE
void CFBasicHashSetCapacity(CFBasicHashRef ht
, CFIndex capacity
) {
1252 if (!CFBasicHashIsMutable(ht
)) HALT
;
1253 if (ht
->bits
.used_buckets
< capacity
) {
1254 ht
->bits
.mutations
++;
1255 __CFBasicHashRehash(ht
, capacity
- ht
->bits
.used_buckets
);
1259 static void __CFBasicHashAddValue(CFBasicHashRef ht
, CFIndex bkt_idx
, uintptr_t stack_key
, uintptr_t stack_value
) {
1260 ht
->bits
.mutations
++;
1261 if (CFBasicHashGetCapacity(ht
) < ht
->bits
.used_buckets
+ 1) {
1262 __CFBasicHashRehash(ht
, 1);
1263 bkt_idx
= __CFBasicHashFindBucket_NoCollision(ht
, stack_key
, 0);
1264 } else if (__CFBasicHashIsDeleted(ht
, bkt_idx
)) {
1267 uintptr_t key_hash
= 0;
1268 if (__CFBasicHashHasHashCache(ht
)) {
1269 key_hash
= __CFBasicHashHashKey(ht
, stack_key
);
1271 stack_value
= __CFBasicHashImportValue(ht
, stack_value
);
1272 if (ht
->bits
.keys_offset
) {
1273 stack_key
= __CFBasicHashImportKey(ht
, stack_key
);
1275 __CFBasicHashSetValue(ht
, bkt_idx
, stack_value
, false, false);
1276 if (ht
->bits
.keys_offset
) {
1277 __CFBasicHashSetKey(ht
, bkt_idx
, stack_key
, false, false);
1279 if (ht
->bits
.counts_offset
) {
1280 __CFBasicHashIncSlotCount(ht
, bkt_idx
);
1282 if (__CFBasicHashHasHashCache(ht
)) {
1283 __CFBasicHashGetHashes(ht
)[bkt_idx
] = key_hash
;
1285 ht
->bits
.used_buckets
++;
1288 static void __CFBasicHashReplaceValue(CFBasicHashRef ht
, CFIndex bkt_idx
, uintptr_t stack_key
, uintptr_t stack_value
) {
1289 ht
->bits
.mutations
++;
1290 stack_value
= __CFBasicHashImportValue(ht
, stack_value
);
1291 if (ht
->bits
.keys_offset
) {
1292 stack_key
= __CFBasicHashImportKey(ht
, stack_key
);
1294 __CFBasicHashSetValue(ht
, bkt_idx
, stack_value
, false, false);
1295 if (ht
->bits
.keys_offset
) {
1296 __CFBasicHashSetKey(ht
, bkt_idx
, stack_key
, false, false);
1300 static void __CFBasicHashRemoveValue(CFBasicHashRef ht
, CFIndex bkt_idx
) {
1301 ht
->bits
.mutations
++;
1302 __CFBasicHashSetValue(ht
, bkt_idx
, ~0UL, false, true);
1303 if (ht
->bits
.keys_offset
) {
1304 __CFBasicHashSetKey(ht
, bkt_idx
, ~0UL, false, true);
1306 if (ht
->bits
.counts_offset
) {
1307 __CFBasicHashDecSlotCount(ht
, bkt_idx
);
1309 if (__CFBasicHashHasHashCache(ht
)) {
1310 __CFBasicHashGetHashes(ht
)[bkt_idx
] = 0;
1312 ht
->bits
.used_buckets
--;
1314 Boolean do_shrink
= false;
1315 if (ht
->bits
.fast_grow
) { // == slow shrink
1316 do_shrink
= (5 < ht
->bits
.num_buckets_idx
&& ht
->bits
.used_buckets
< __CFBasicHashGetCapacityForNumBuckets(ht
, ht
->bits
.num_buckets_idx
- 5));
1318 do_shrink
= (2 < ht
->bits
.num_buckets_idx
&& ht
->bits
.used_buckets
< __CFBasicHashGetCapacityForNumBuckets(ht
, ht
->bits
.num_buckets_idx
- 2));
1321 __CFBasicHashRehash(ht
, -1);
1324 do_shrink
= (0 == ht
->bits
.deleted
); // .deleted roll-over
1325 CFIndex num_buckets
= __CFBasicHashTableSizes
[ht
->bits
.num_buckets_idx
];
1326 do_shrink
= do_shrink
|| ((20 <= num_buckets
) && (num_buckets
/ 4 <= ht
->bits
.deleted
));
1328 __CFBasicHashRehash(ht
, 0);
1332 CF_PRIVATE Boolean
CFBasicHashAddValue(CFBasicHashRef ht
, uintptr_t stack_key
, uintptr_t stack_value
) {
1333 if (!CFBasicHashIsMutable(ht
)) HALT
;
1334 if (__CFBasicHashSubABZero
== stack_key
) HALT
;
1335 if (__CFBasicHashSubABOne
== stack_key
) HALT
;
1336 if (__CFBasicHashSubABZero
== stack_value
) HALT
;
1337 if (__CFBasicHashSubABOne
== stack_value
) HALT
;
1338 CFBasicHashBucket bkt
= __CFBasicHashFindBucket(ht
, stack_key
);
1339 if (0 < bkt
.count
) {
1340 ht
->bits
.mutations
++;
1341 if (ht
->bits
.counts_offset
&& bkt
.count
< LONG_MAX
) { // if not yet as large as a CFIndex can be... otherwise clamp and do nothing
1342 __CFBasicHashIncSlotCount(ht
, bkt
.idx
);
1346 __CFBasicHashAddValue(ht
, bkt
.idx
, stack_key
, stack_value
);
1352 CF_PRIVATE
void CFBasicHashReplaceValue(CFBasicHashRef ht
, uintptr_t stack_key
, uintptr_t stack_value
) {
1353 if (!CFBasicHashIsMutable(ht
)) HALT
;
1354 if (__CFBasicHashSubABZero
== stack_key
) HALT
;
1355 if (__CFBasicHashSubABOne
== stack_key
) HALT
;
1356 if (__CFBasicHashSubABZero
== stack_value
) HALT
;
1357 if (__CFBasicHashSubABOne
== stack_value
) HALT
;
1358 CFBasicHashBucket bkt
= __CFBasicHashFindBucket(ht
, stack_key
);
1359 if (0 < bkt
.count
) {
1360 __CFBasicHashReplaceValue(ht
, bkt
.idx
, stack_key
, stack_value
);
1364 CF_PRIVATE
void CFBasicHashSetValue(CFBasicHashRef ht
, uintptr_t stack_key
, uintptr_t stack_value
) {
1365 if (!CFBasicHashIsMutable(ht
)) HALT
;
1366 if (__CFBasicHashSubABZero
== stack_key
) HALT
;
1367 if (__CFBasicHashSubABOne
== stack_key
) HALT
;
1368 if (__CFBasicHashSubABZero
== stack_value
) HALT
;
1369 if (__CFBasicHashSubABOne
== stack_value
) HALT
;
1370 CFBasicHashBucket bkt
= __CFBasicHashFindBucket(ht
, stack_key
);
1371 if (0 < bkt
.count
) {
1372 __CFBasicHashReplaceValue(ht
, bkt
.idx
, stack_key
, stack_value
);
1374 __CFBasicHashAddValue(ht
, bkt
.idx
, stack_key
, stack_value
);
1378 CF_PRIVATE CFIndex
CFBasicHashRemoveValue(CFBasicHashRef ht
, uintptr_t stack_key
) {
1379 if (!CFBasicHashIsMutable(ht
)) HALT
;
1380 if (__CFBasicHashSubABZero
== stack_key
|| __CFBasicHashSubABOne
== stack_key
) return 0;
1381 CFBasicHashBucket bkt
= __CFBasicHashFindBucket(ht
, stack_key
);
1382 if (1 < bkt
.count
) {
1383 ht
->bits
.mutations
++;
1384 if (ht
->bits
.counts_offset
&& bkt
.count
< LONG_MAX
) { // if not as large as a CFIndex can be... otherwise clamp and do nothing
1385 __CFBasicHashDecSlotCount(ht
, bkt
.idx
);
1387 } else if (0 < bkt
.count
) {
1388 __CFBasicHashRemoveValue(ht
, bkt
.idx
);
1393 CF_PRIVATE CFIndex
CFBasicHashRemoveValueAtIndex(CFBasicHashRef ht
, CFIndex idx
) {
1394 if (!CFBasicHashIsMutable(ht
)) HALT
;
1395 CFBasicHashBucket bkt
= CFBasicHashGetBucket(ht
, idx
);
1396 if (1 < bkt
.count
) {
1397 ht
->bits
.mutations
++;
1398 if (ht
->bits
.counts_offset
&& bkt
.count
< LONG_MAX
) { // if not as large as a CFIndex can be... otherwise clamp and do nothing
1399 __CFBasicHashDecSlotCount(ht
, bkt
.idx
);
1401 } else if (0 < bkt
.count
) {
1402 __CFBasicHashRemoveValue(ht
, bkt
.idx
);
1407 CF_PRIVATE
void CFBasicHashRemoveAllValues(CFBasicHashRef ht
) {
1408 if (!CFBasicHashIsMutable(ht
)) HALT
;
1409 if (0 == ht
->bits
.num_buckets_idx
) return;
1410 __CFBasicHashDrain(ht
, false);
1413 CF_PRIVATE Boolean
CFBasicHashAddIntValueAndInc(CFBasicHashRef ht
, uintptr_t stack_key
, uintptr_t int_value
) {
1414 if (!CFBasicHashIsMutable(ht
)) HALT
;
1415 if (__CFBasicHashSubABZero
== stack_key
) HALT
;
1416 if (__CFBasicHashSubABOne
== stack_key
) HALT
;
1417 if (__CFBasicHashSubABZero
== int_value
) HALT
;
1418 if (__CFBasicHashSubABOne
== int_value
) HALT
;
1419 CFBasicHashBucket bkt
= __CFBasicHashFindBucket(ht
, stack_key
);
1420 if (0 < bkt
.count
) {
1421 ht
->bits
.mutations
++;
1423 // must rehash before renumbering
1424 if (CFBasicHashGetCapacity(ht
) < ht
->bits
.used_buckets
+ 1) {
1425 __CFBasicHashRehash(ht
, 1);
1426 bkt
.idx
= __CFBasicHashFindBucket_NoCollision(ht
, stack_key
, 0);
1428 CFIndex cnt
= (CFIndex
)__CFBasicHashTableSizes
[ht
->bits
.num_buckets_idx
];
1429 for (CFIndex idx
= 0; idx
< cnt
; idx
++) {
1430 if (!__CFBasicHashIsEmptyOrDeleted(ht
, idx
)) {
1431 uintptr_t stack_value
= __CFBasicHashGetValue(ht
, idx
);
1432 if (int_value
<= stack_value
) {
1434 __CFBasicHashSetValue(ht
, idx
, stack_value
, true, false);
1435 ht
->bits
.mutations
++;
1439 __CFBasicHashAddValue(ht
, bkt
.idx
, stack_key
, int_value
);
1445 CF_PRIVATE
void CFBasicHashRemoveIntValueAndDec(CFBasicHashRef ht
, uintptr_t int_value
) {
1446 if (!CFBasicHashIsMutable(ht
)) HALT
;
1447 if (__CFBasicHashSubABZero
== int_value
) HALT
;
1448 if (__CFBasicHashSubABOne
== int_value
) HALT
;
1449 uintptr_t bkt_idx
= ~0UL;
1450 CFIndex cnt
= (CFIndex
)__CFBasicHashTableSizes
[ht
->bits
.num_buckets_idx
];
1451 for (CFIndex idx
= 0; idx
< cnt
; idx
++) {
1452 if (!__CFBasicHashIsEmptyOrDeleted(ht
, idx
)) {
1453 uintptr_t stack_value
= __CFBasicHashGetValue(ht
, idx
);
1454 if (int_value
== stack_value
) {
1457 if (int_value
< stack_value
) {
1459 __CFBasicHashSetValue(ht
, idx
, stack_value
, true, false);
1460 ht
->bits
.mutations
++;
1464 __CFBasicHashRemoveValue(ht
, bkt_idx
);
1467 CF_PRIVATE
size_t CFBasicHashGetSize(CFConstBasicHashRef ht
, Boolean total
) {
1468 size_t size
= sizeof(struct __CFBasicHash
);
1469 if (ht
->bits
.keys_offset
) size
+= sizeof(CFBasicHashValue
*);
1470 if (ht
->bits
.counts_offset
) size
+= sizeof(void *);
1471 if (__CFBasicHashHasHashCache(ht
)) size
+= sizeof(uintptr_t *);
1473 CFIndex num_buckets
= __CFBasicHashTableSizes
[ht
->bits
.num_buckets_idx
];
1474 if (0 < num_buckets
) {
1475 size
+= malloc_size(__CFBasicHashGetValues(ht
));
1476 if (ht
->bits
.keys_offset
) size
+= malloc_size(__CFBasicHashGetKeys(ht
));
1477 if (ht
->bits
.counts_offset
) size
+= malloc_size(__CFBasicHashGetCounts(ht
));
1478 if (__CFBasicHashHasHashCache(ht
)) size
+= malloc_size(__CFBasicHashGetHashes(ht
));
1484 CF_PRIVATE CFStringRef
CFBasicHashCopyDescription(CFConstBasicHashRef ht
, Boolean detailed
, CFStringRef prefix
, CFStringRef entryPrefix
, Boolean describeElements
) {
1485 CFMutableStringRef result
= CFStringCreateMutable(kCFAllocatorSystemDefault
, 0);
1486 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
));
1488 const char *cb_type
= "custom";
1489 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
);
1490 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
);
1491 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"));
1492 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));
1493 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
));
1495 CFStringAppendFormat(result
, NULL
, CFSTR("%@entries =>\n"), prefix
);
1496 CFBasicHashApply(ht
, ^(CFBasicHashBucket bkt
) {
1497 CFStringRef vDesc
= NULL
, kDesc
= NULL
;
1498 if (!describeElements
) {
1499 vDesc
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("<%p>"), (void *)bkt
.weak_value
);
1500 if (ht
->bits
.keys_offset
) {
1501 kDesc
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("<%p>"), (void *)bkt
.weak_key
);
1504 vDesc
= __CFBasicHashDescValue(ht
, bkt
.weak_value
);
1505 if (ht
->bits
.keys_offset
) {
1506 kDesc
= __CFBasicHashDescKey(ht
, bkt
.weak_key
);
1509 if (ht
->bits
.keys_offset
&& ht
->bits
.counts_offset
) {
1510 CFStringAppendFormat(result
, NULL
, CFSTR("%@%ld : %@ = %@ (%ld)\n"), entryPrefix
, bkt
.idx
, kDesc
, vDesc
, bkt
.count
);
1511 } else if (ht
->bits
.keys_offset
) {
1512 CFStringAppendFormat(result
, NULL
, CFSTR("%@%ld : %@ = %@\n"), entryPrefix
, bkt
.idx
, kDesc
, vDesc
);
1513 } else if (ht
->bits
.counts_offset
) {
1514 CFStringAppendFormat(result
, NULL
, CFSTR("%@%ld : %@ (%ld)\n"), entryPrefix
, bkt
.idx
, vDesc
, bkt
.count
);
1516 CFStringAppendFormat(result
, NULL
, CFSTR("%@%ld : %@\n"), entryPrefix
, bkt
.idx
, vDesc
);
1518 if (kDesc
) CFRelease(kDesc
);
1519 if (vDesc
) CFRelease(vDesc
);
1520 return (Boolean
)true;
1522 CFStringAppendFormat(result
, NULL
, CFSTR("%@}\n"), prefix
);
1526 CF_PRIVATE
void CFBasicHashShow(CFConstBasicHashRef ht
) {
1527 CFStringRef str
= CFBasicHashCopyDescription(ht
, true, CFSTR(""), CFSTR("\t"), false);
1532 CF_PRIVATE Boolean
__CFBasicHashEqual(CFTypeRef cf1
, CFTypeRef cf2
) {
1533 CFBasicHashRef ht1
= (CFBasicHashRef
)cf1
;
1534 CFBasicHashRef ht2
= (CFBasicHashRef
)cf2
;
1535 //#warning this used to require that the key and value equal callbacks were pointer identical
1536 return CFBasicHashesAreEqual(ht1
, ht2
);
1539 CF_PRIVATE CFHashCode
__CFBasicHashHash(CFTypeRef cf
) {
1540 CFBasicHashRef ht
= (CFBasicHashRef
)cf
;
1541 return CFBasicHashGetCount(ht
);
1544 CF_PRIVATE CFStringRef
__CFBasicHashCopyDescription(CFTypeRef cf
) {
1545 CFBasicHashRef ht
= (CFBasicHashRef
)cf
;
1546 CFStringRef desc
= CFBasicHashCopyDescription(ht
, false, CFSTR(""), CFSTR("\t"), true);
1547 CFStringRef result
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("<CFBasicHash %p [%p]>%@"), cf
, CFGetAllocator(cf
), desc
);
1552 CF_PRIVATE
void __CFBasicHashDeallocate(CFTypeRef cf
) {
1553 CFBasicHashRef ht
= (CFBasicHashRef
)cf
;
1554 if (ht
->bits
.finalized
) HALT
;
1555 ht
->bits
.finalized
= 1;
1556 __CFBasicHashDrain(ht
, true);
1557 #if ENABLE_MEMORY_COUNTERS
1558 OSAtomicAdd64Barrier(-1, &__CFBasicHashTotalCount
);
1559 OSAtomicAdd32Barrier(-1, &__CFBasicHashSizes
[ht
->bits
.num_buckets_idx
]);
1563 static CFTypeID __kCFBasicHashTypeID
= _kCFRuntimeNotATypeID
;
1565 static const CFRuntimeClass __CFBasicHashClass
= {
1566 _kCFRuntimeScannedObject
,
1570 __CFBasicHashDeallocate
,
1574 __CFBasicHashCopyDescription
1577 CF_PRIVATE CFTypeID
CFBasicHashGetTypeID(void) {
1578 static dispatch_once_t initOnce
;
1579 dispatch_once(&initOnce
, ^{ __kCFBasicHashTypeID
= _CFRuntimeRegisterClass(&__CFBasicHashClass
); });
1580 return __kCFBasicHashTypeID
;
1583 CF_PRIVATE CFBasicHashRef
CFBasicHashCreate(CFAllocatorRef allocator
, CFOptionFlags flags
, const CFBasicHashCallbacks
*cb
) {
1584 size_t size
= sizeof(struct __CFBasicHash
) - sizeof(CFRuntimeBase
);
1585 if (flags
& kCFBasicHashHasKeys
) size
+= sizeof(CFBasicHashValue
*); // keys
1586 if (flags
& kCFBasicHashHasCounts
) size
+= sizeof(void *); // counts
1587 if (flags
& kCFBasicHashHasHashCache
) size
+= sizeof(uintptr_t *); // hashes
1588 CFBasicHashRef ht
= (CFBasicHashRef
)_CFRuntimeCreateInstance(allocator
, CFBasicHashGetTypeID(), size
, NULL
);
1589 if (NULL
== ht
) return NULL
;
1591 ht
->bits
.finalized
= 0;
1592 ht
->bits
.hash_style
= (flags
>> 13) & 0x3;
1593 ht
->bits
.fast_grow
= (flags
& kCFBasicHashAggressiveGrowth
) ? 1 : 0;
1594 ht
->bits
.counts_width
= 0;
1595 ht
->bits
.strong_values
= (flags
& kCFBasicHashStrongValues
) ? 1 : 0;
1596 ht
->bits
.strong_keys
= (flags
& kCFBasicHashStrongKeys
) ? 1 : 0;
1597 ht
->bits
.weak_values
= (flags
& kCFBasicHashWeakValues
) ? 1 : 0;
1598 ht
->bits
.weak_keys
= (flags
& kCFBasicHashWeakKeys
) ? 1 : 0;
1599 ht
->bits
.int_values
= (flags
& kCFBasicHashIntegerValues
) ? 1 : 0;
1600 ht
->bits
.int_keys
= (flags
& kCFBasicHashIntegerKeys
) ? 1 : 0;
1601 ht
->bits
.indirect_keys
= (flags
& kCFBasicHashIndirectKeys
) ? 1 : 0;
1602 ht
->bits
.num_buckets_idx
= 0;
1603 ht
->bits
.used_buckets
= 0;
1604 ht
->bits
.deleted
= 0;
1605 ht
->bits
.mutations
= 1;
1607 if (ht
->bits
.strong_values
&& ht
->bits
.weak_values
) HALT
;
1608 if (ht
->bits
.strong_values
&& ht
->bits
.int_values
) HALT
;
1609 if (ht
->bits
.strong_keys
&& ht
->bits
.weak_keys
) HALT
;
1610 if (ht
->bits
.strong_keys
&& ht
->bits
.int_keys
) HALT
;
1611 if (ht
->bits
.weak_values
&& ht
->bits
.int_values
) HALT
;
1612 if (ht
->bits
.weak_keys
&& ht
->bits
.int_keys
) HALT
;
1613 if (ht
->bits
.indirect_keys
&& ht
->bits
.strong_keys
) HALT
;
1614 if (ht
->bits
.indirect_keys
&& ht
->bits
.weak_keys
) HALT
;
1615 if (ht
->bits
.indirect_keys
&& ht
->bits
.int_keys
) HALT
;
1617 uint64_t offset
= 1;
1618 ht
->bits
.keys_offset
= (flags
& kCFBasicHashHasKeys
) ? offset
++ : 0;
1619 ht
->bits
.counts_offset
= (flags
& kCFBasicHashHasCounts
) ? offset
++ : 0;
1620 ht
->bits
.hashes_offset
= (flags
& kCFBasicHashHasHashCache
) ? offset
++ : 0;
1622 #if DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
1623 ht
->bits
.hashes_offset
= 0;
1624 ht
->bits
.strong_values
= 0;
1625 ht
->bits
.strong_keys
= 0;
1626 ht
->bits
.weak_values
= 0;
1627 ht
->bits
.weak_keys
= 0;
1630 ht
->bits
.__kret
= CFBasicHashGetPtrIndex((void *)cb
->retainKey
);
1631 ht
->bits
.__vret
= CFBasicHashGetPtrIndex((void *)cb
->retainValue
);
1632 ht
->bits
.__krel
= CFBasicHashGetPtrIndex((void *)cb
->releaseKey
);
1633 ht
->bits
.__vrel
= CFBasicHashGetPtrIndex((void *)cb
->releaseValue
);
1634 ht
->bits
.__kdes
= CFBasicHashGetPtrIndex((void *)cb
->copyKeyDescription
);
1635 ht
->bits
.__vdes
= CFBasicHashGetPtrIndex((void *)cb
->copyValueDescription
);
1636 ht
->bits
.__kequ
= CFBasicHashGetPtrIndex((void *)cb
->equateKeys
);
1637 ht
->bits
.__vequ
= CFBasicHashGetPtrIndex((void *)cb
->equateValues
);
1638 ht
->bits
.__khas
= CFBasicHashGetPtrIndex((void *)cb
->hashKey
);
1639 ht
->bits
.__kget
= CFBasicHashGetPtrIndex((void *)cb
->getIndirectKey
);
1641 for (CFIndex idx
= 0; idx
< offset
; idx
++) {
1642 ht
->pointers
[idx
] = NULL
;
1645 #if ENABLE_MEMORY_COUNTERS
1646 int64_t size_now
= OSAtomicAdd64Barrier((int64_t) CFBasicHashGetSize(ht
, true), & __CFBasicHashTotalSize
);
1647 while (__CFBasicHashPeakSize
< size_now
&& !OSAtomicCompareAndSwap64Barrier(__CFBasicHashPeakSize
, size_now
, & __CFBasicHashPeakSize
));
1648 int64_t count_now
= OSAtomicAdd64Barrier(1, & __CFBasicHashTotalCount
);
1649 while (__CFBasicHashPeakCount
< count_now
&& !OSAtomicCompareAndSwap64Barrier(__CFBasicHashPeakCount
, count_now
, & __CFBasicHashPeakCount
));
1650 OSAtomicAdd32Barrier(1, &__CFBasicHashSizes
[ht
->bits
.num_buckets_idx
]);
1656 CF_PRIVATE CFBasicHashRef
CFBasicHashCreateCopy(CFAllocatorRef allocator
, CFConstBasicHashRef src_ht
) {
1657 size_t size
= CFBasicHashGetSize(src_ht
, false) - sizeof(CFRuntimeBase
);
1658 CFIndex new_num_buckets
= __CFBasicHashTableSizes
[src_ht
->bits
.num_buckets_idx
];
1659 CFBasicHashValue
*new_values
= NULL
, *new_keys
= NULL
;
1660 void *new_counts
= NULL
;
1661 uintptr_t *new_hashes
= NULL
;
1663 if (0 < new_num_buckets
) {
1664 Boolean strongValues
= CFBasicHashHasStrongValues(src_ht
) && !(kCFUseCollectableAllocator
&& !CF_IS_COLLECTABLE_ALLOCATOR(allocator
));
1665 Boolean strongKeys
= CFBasicHashHasStrongKeys(src_ht
) && !(kCFUseCollectableAllocator
&& !CF_IS_COLLECTABLE_ALLOCATOR(allocator
));
1666 new_values
= (CFBasicHashValue
*)__CFBasicHashAllocateMemory2(allocator
, new_num_buckets
, sizeof(CFBasicHashValue
), strongValues
, 0);
1667 if (!new_values
) return NULL
; // in this unusual circumstance, leak previously allocated blocks for now
1668 __SetLastAllocationEventName(new_values
, "CFBasicHash (value-store)");
1669 if (src_ht
->bits
.keys_offset
) {
1670 new_keys
= (CFBasicHashValue
*)__CFBasicHashAllocateMemory2(allocator
, new_num_buckets
, sizeof(CFBasicHashValue
), strongKeys
, false);
1671 if (!new_keys
) return NULL
; // in this unusual circumstance, leak previously allocated blocks for now
1672 __SetLastAllocationEventName(new_keys
, "CFBasicHash (key-store)");
1674 if (src_ht
->bits
.counts_offset
) {
1675 new_counts
= (uintptr_t *)__CFBasicHashAllocateMemory2(allocator
, new_num_buckets
, (1 << src_ht
->bits
.counts_width
), false, false);
1676 if (!new_counts
) return NULL
; // in this unusual circumstance, leak previously allocated blocks for now
1677 __SetLastAllocationEventName(new_counts
, "CFBasicHash (count-store)");
1679 if (__CFBasicHashHasHashCache(src_ht
)) {
1680 new_hashes
= (uintptr_t *)__CFBasicHashAllocateMemory2(allocator
, new_num_buckets
, sizeof(uintptr_t), false, false);
1681 if (!new_hashes
) return NULL
; // in this unusual circumstance, leak previously allocated blocks for now
1682 __SetLastAllocationEventName(new_hashes
, "CFBasicHash (hash-store)");
1686 CFBasicHashRef ht
= (CFBasicHashRef
)_CFRuntimeCreateInstance(allocator
, CFBasicHashGetTypeID(), size
, NULL
);
1687 if (NULL
== ht
) return NULL
; // in this unusual circumstance, leak previously allocated blocks for now
1689 memmove((uint8_t *)ht
+ sizeof(CFRuntimeBase
), (uint8_t *)src_ht
+ sizeof(CFRuntimeBase
), sizeof(ht
->bits
));
1690 if (kCFUseCollectableAllocator
&& !CF_IS_COLLECTABLE_ALLOCATOR(allocator
)) {
1691 ht
->bits
.strong_values
= 0;
1692 ht
->bits
.strong_keys
= 0;
1693 ht
->bits
.weak_values
= 0;
1694 ht
->bits
.weak_keys
= 0;
1696 ht
->bits
.finalized
= 0;
1697 ht
->bits
.mutations
= 1;
1699 if (0 == new_num_buckets
) {
1700 #if ENABLE_MEMORY_COUNTERS
1701 int64_t size_now
= OSAtomicAdd64Barrier((int64_t) CFBasicHashGetSize(ht
, true), & __CFBasicHashTotalSize
);
1702 while (__CFBasicHashPeakSize
< size_now
&& !OSAtomicCompareAndSwap64Barrier(__CFBasicHashPeakSize
, size_now
, & __CFBasicHashPeakSize
));
1703 int64_t count_now
= OSAtomicAdd64Barrier(1, & __CFBasicHashTotalCount
);
1704 while (__CFBasicHashPeakCount
< count_now
&& !OSAtomicCompareAndSwap64Barrier(__CFBasicHashPeakCount
, count_now
, & __CFBasicHashPeakCount
));
1705 OSAtomicAdd32Barrier(1, &__CFBasicHashSizes
[ht
->bits
.num_buckets_idx
]);
1710 CFBasicHashValue
*old_values
= NULL
, *old_keys
= NULL
;
1711 void *old_counts
= NULL
;
1712 uintptr_t *old_hashes
= NULL
;
1714 old_values
= __CFBasicHashGetValues(src_ht
);
1715 if (src_ht
->bits
.keys_offset
) {
1716 old_keys
= __CFBasicHashGetKeys(src_ht
);
1718 if (src_ht
->bits
.counts_offset
) {
1719 old_counts
= __CFBasicHashGetCounts(src_ht
);
1721 if (__CFBasicHashHasHashCache(src_ht
)) {
1722 old_hashes
= __CFBasicHashGetHashes(src_ht
);
1725 __CFBasicHashSetValues(ht
, new_values
);
1727 __CFBasicHashSetKeys(ht
, new_keys
);
1730 __CFBasicHashSetCounts(ht
, new_counts
);
1733 __CFBasicHashSetHashes(ht
, new_hashes
);
1736 for (CFIndex idx
= 0; idx
< new_num_buckets
; idx
++) {
1737 uintptr_t stack_value
= old_values
[idx
].neutral
;
1738 if (stack_value
!= 0UL && stack_value
!= ~0UL) {
1739 uintptr_t old_value
= stack_value
;
1740 if (__CFBasicHashSubABZero
== old_value
) old_value
= 0UL;
1741 if (__CFBasicHashSubABOne
== old_value
) old_value
= ~0UL;
1742 __CFBasicHashSetValue(ht
, idx
, __CFBasicHashImportValue(ht
, old_value
), true, false);
1744 uintptr_t old_key
= old_keys
[idx
].neutral
;
1745 if (__CFBasicHashSubABZero
== old_key
) old_key
= 0UL;
1746 if (__CFBasicHashSubABOne
== old_key
) old_key
= ~0UL;
1747 __CFBasicHashSetKey(ht
, idx
, __CFBasicHashImportKey(ht
, old_key
), true, false);
1750 __CFBasicHashSetValue(ht
, idx
, stack_value
, true, true);
1752 __CFBasicHashSetKey(ht
, idx
, stack_value
, true, true);
1756 if (new_counts
) memmove(new_counts
, old_counts
, new_num_buckets
* (1 << ht
->bits
.counts_width
));
1757 if (new_hashes
) memmove(new_hashes
, old_hashes
, new_num_buckets
* sizeof(uintptr_t));
1759 #if ENABLE_MEMORY_COUNTERS
1760 int64_t size_now
= OSAtomicAdd64Barrier((int64_t) CFBasicHashGetSize(ht
, true), & __CFBasicHashTotalSize
);
1761 while (__CFBasicHashPeakSize
< size_now
&& !OSAtomicCompareAndSwap64Barrier(__CFBasicHashPeakSize
, size_now
, & __CFBasicHashPeakSize
));
1762 int64_t count_now
= OSAtomicAdd64Barrier(1, & __CFBasicHashTotalCount
);
1763 while (__CFBasicHashPeakCount
< count_now
&& !OSAtomicCompareAndSwap64Barrier(__CFBasicHashPeakCount
, count_now
, & __CFBasicHashPeakCount
));
1764 OSAtomicAdd32Barrier(1, &__CFBasicHashSizes
[ht
->bits
.num_buckets_idx
]);