]> git.saurik.com Git - apple/cf.git/blob - CFBasicHash.c
CF-1153.18.tar.gz
[apple/cf.git] / CFBasicHash.c
1 /*
2 * Copyright (c) 2015 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /* CFBasicHash.m
25 Copyright (c) 2008-2014, Apple Inc. All rights reserved.
26 Responsibility: Christopher Kane
27 */
28
29 #import "CFBasicHash.h"
30 #import <CoreFoundation/CFRuntime.h>
31 #import <CoreFoundation/CFSet.h>
32 #import <Block.h>
33 #import <math.h>
34 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
35 #import <dispatch/dispatch.h>
36 #endif
37
38 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
39 #define __SetLastAllocationEventName(A, B) do { if (__CFOASafe && (A)) __CFSetLastAllocationEventName(A, B); } while (0)
40 #else
41 #define __SetLastAllocationEventName(A, B) do { } while (0)
42 #endif
43
44 #define __AssignWithWriteBarrier(location, value) objc_assign_strongCast((id)value, (id *)location)
45
46 #define ENABLE_DTRACE_PROBES 0
47 #define ENABLE_MEMORY_COUNTERS 0
48
49 #if defined(DTRACE_PROBES_DISABLED) && DTRACE_PROBES_DISABLED
50 #undef ENABLE_DTRACE_PROBES
51 #define ENABLE_DTRACE_PROBES 0
52 #endif
53
54 /*
55 // dtrace -h -s foo.d
56 // Note: output then changed by casts of the arguments
57 // dtrace macros last generated 2010-09-08 on 10.7 prerelease (11A259)
58
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);
69 };
70
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
76 */
77
78 #if ENABLE_DTRACE_PROBES
79
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"
81
82 #define COCOA_HASHTABLE_TYPEDEFS "___dtrace_typedefs$Cocoa_HashTable$v2"
83
84 #define COCOA_HASHTABLE_REHASH_END(arg0, arg1, arg2) \
85 do { \
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); \
89 } while (0)
90 #define COCOA_HASHTABLE_REHASH_END_ENABLED() \
91 ({ int _r = __dtrace_isenabled$Cocoa_HashTable$rehash_end$v1(); \
92 __asm__ volatile(""); \
93 _r; })
94 #define COCOA_HASHTABLE_REHASH_START(arg0, arg1, arg2) \
95 do { \
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); \
99 } while (0)
100 #define COCOA_HASHTABLE_REHASH_START_ENABLED() \
101 ({ int _r = __dtrace_isenabled$Cocoa_HashTable$rehash_start$v1(); \
102 __asm__ volatile(""); \
103 _r; })
104 #define COCOA_HASHTABLE_HASH_KEY(arg0, arg1, arg2) \
105 do { \
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); \
109 } while (0)
110 #define COCOA_HASHTABLE_HASH_KEY_ENABLED() \
111 ({ int _r = __dtrace_isenabled$Cocoa_HashTable$hash_key$v1(); \
112 __asm__ volatile(""); \
113 _r; })
114 #define COCOA_HASHTABLE_PROBE_DELETED(arg0, arg1) \
115 do { \
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); \
119 } while (0)
120 #define COCOA_HASHTABLE_PROBE_DELETED_ENABLED() \
121 ({ int _r = __dtrace_isenabled$Cocoa_HashTable$probe_deleted$v1(); \
122 __asm__ volatile(""); \
123 _r; })
124 #define COCOA_HASHTABLE_PROBE_EMPTY(arg0, arg1) \
125 do { \
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); \
129 } while (0)
130 #define COCOA_HASHTABLE_PROBE_EMPTY_ENABLED() \
131 ({ int _r = __dtrace_isenabled$Cocoa_HashTable$probe_empty$v1(); \
132 __asm__ volatile(""); \
133 _r; })
134 #define COCOA_HASHTABLE_PROBE_VALID(arg0, arg1) \
135 do { \
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); \
139 } while (0)
140 #define COCOA_HASHTABLE_PROBE_VALID_ENABLED() \
141 ({ int _r = __dtrace_isenabled$Cocoa_HashTable$probe_valid$v1(); \
142 __asm__ volatile(""); \
143 _r; })
144 #define COCOA_HASHTABLE_PROBING_END(arg0, arg1) \
145 do { \
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); \
149 } while (0)
150 #define COCOA_HASHTABLE_PROBING_END_ENABLED() \
151 ({ int _r = __dtrace_isenabled$Cocoa_HashTable$probing_end$v1(); \
152 __asm__ volatile(""); \
153 _r; })
154 #define COCOA_HASHTABLE_PROBING_START(arg0, arg1) \
155 do { \
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); \
159 } while (0)
160 #define COCOA_HASHTABLE_PROBING_START_ENABLED() \
161 ({ int _r = __dtrace_isenabled$Cocoa_HashTable$probing_start$v1(); \
162 __asm__ volatile(""); \
163 _r; })
164 #define COCOA_HASHTABLE_TEST_EQUAL(arg0, arg1, arg2) \
165 do { \
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); \
169 } while (0)
170 #define COCOA_HASHTABLE_TEST_EQUAL_ENABLED() \
171 ({ int _r = __dtrace_isenabled$Cocoa_HashTable$test_equal$v1(); \
172 __asm__ volatile(""); \
173 _r; })
174
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);
193
194 #else
195
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
214
215 #endif
216
217
218 #if !defined(__LP64__)
219 #define __LP64__ 0
220 #endif
221
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,
231 #if __LP64__
232 765180413UL, 1238087663UL, 2003267557UL, 3241355263UL, 5244622819UL,
233 #if 0
234 8485977589UL, 13730600407UL, 22216578047UL, 35947178479UL,
235 58163756537UL, 94110934997UL, 152274691561UL, 246385626107UL,
236 398660317687UL, 645045943807UL, 1043706260983UL, 1688752204787UL,
237 2732458465769UL, 4421210670577UL, 7153669136377UL,
238 11574879807461UL, 18728548943849UL, 30303428750843UL
239 #endif
240 #endif
241 };
242
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,
249 #if __LP64__
250 472907503UL, 765180257UL, 1238087439UL, 2003267722UL, 3241355160UL,
251 #if 0
252 5244622578UL, 8485977737UL, 13730600347UL, 22216578100UL,
253 35947178453UL, 58163756541UL, 94110935011UL, 152274691274UL,
254 246385626296UL, 398660317578UL, 645045943559UL, 1043706261135UL,
255 1688752204693UL, 2732458465840UL, 4421210670552UL,
256 7153669136706UL, 11574879807265UL, 18728548943682UL
257 #endif
258 #endif
259 };
260
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,
266 3, 3, 5, 2, 22, 2,
267 11, 5, 5, 2,
268 #if __LP64__
269 3, 10, 2, 3, 10,
270 2, 3, 5, 3,
271 3, 2, 7, 2,
272 3, 3, 3, 2,
273 3, 5, 5,
274 2, 3, 2
275 #endif
276 };
277
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);
283 } else {
284 new_mem = CFAllocatorAllocate(allocator, count * elem_size, 0);
285 }
286 return new_mem;
287 }
288
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);
293 } else {
294 new_mem = CFAllocatorAllocate(allocator, count * elem_size, 0);
295 }
296 return new_mem;
297 }
298
299 #define __CFBasicHashSubABZero 0xa7baadb1
300 #define __CFBasicHashSubABOne 0xa5baadb9
301
302 typedef union {
303 uintptr_t neutral;
304 id strong;
305 id weak;
306 } CFBasicHashValue;
307
308 struct __CFBasicHash {
309 CFRuntimeBase base;
310 struct { // 192 bits
311 uint16_t mutations;
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;
320 uint8_t weak_keys:1;
321 uint8_t int_values:1;
322 uint8_t int_keys:1;
323 uint8_t indirect_keys:1;
324 uint32_t used_buckets; /* number of used buckets */
325 uint64_t deleted:16;
326 uint64_t num_buckets_idx:8; /* index to number of buckets */
327 uint64_t __kret:10;
328 uint64_t __vret:10;
329 uint64_t __krel:10;
330 uint64_t __vrel:10;
331 uint64_t __:1;
332 uint64_t null_rc:1;
333 uint64_t fast_grow:1;
334 uint64_t finalized:1;
335 uint64_t __kdes:10;
336 uint64_t __vdes:10;
337 uint64_t __kequ:10;
338 uint64_t __vequ:10;
339 uint64_t __khas:10;
340 uint64_t __kget:10;
341 } bits;
342 void *pointers[1];
343 };
344
345 static void *CFBasicHashCallBackPtrs[(1UL << 10)];
346 static int32_t CFBasicHashCallBackPtrsCount = 0;
347
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;
360 });
361
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.
366
367 int32_t idx;
368 for (idx = 0; idx < CFBasicHashCallBackPtrsCount; idx++) {
369 if (CFBasicHashCallBackPtrs[idx] == ptr) return idx;
370 }
371
372 if (1000 < CFBasicHashCallBackPtrsCount) HALT;
373 idx = OSAtomicIncrement32(&CFBasicHashCallBackPtrsCount); // returns new value
374 CFBasicHashCallBackPtrs[idx - 1] = ptr;
375 return idx - 1;
376 }
377
378 CF_PRIVATE Boolean CFBasicHashHasStrongValues(CFConstBasicHashRef ht) {
379 #if DEPLOYMENT_TARGET_MACOSX
380 return ht->bits.strong_values ? true : false;
381 #else
382 return false;
383 #endif
384 }
385
386 CF_PRIVATE Boolean CFBasicHashHasStrongKeys(CFConstBasicHashRef ht) {
387 #if DEPLOYMENT_TARGET_MACOSX
388 return ht->bits.strong_keys ? true : false;
389 #else
390 return false;
391 #endif
392 }
393
394 CF_INLINE Boolean __CFBasicHashHasHashCache(CFConstBasicHashRef ht) {
395 #if DEPLOYMENT_TARGET_MACOSX
396 return ht->bits.hashes_offset ? true : false;
397 #else
398 return false;
399 #endif
400 }
401
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);
407 }
408
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);
414 }
415
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);
421 }
422
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);
428 }
429
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);
434 }
435
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);
440 }
441
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);
446 }
447
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);
453 }
454
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);
459 return hash_code;
460 }
461
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);
466 }
467
468 CF_INLINE CFBasicHashValue *__CFBasicHashGetValues(CFConstBasicHashRef ht) {
469 return (CFBasicHashValue *)ht->pointers[0];
470 }
471
472 CF_INLINE void __CFBasicHashSetValues(CFBasicHashRef ht, CFBasicHashValue *ptr) {
473 __AssignWithWriteBarrier(&ht->pointers[0], ptr);
474 }
475
476 CF_INLINE CFBasicHashValue *__CFBasicHashGetKeys(CFConstBasicHashRef ht) {
477 return (CFBasicHashValue *)ht->pointers[ht->bits.keys_offset];
478 }
479
480 CF_INLINE void __CFBasicHashSetKeys(CFBasicHashRef ht, CFBasicHashValue *ptr) {
481 __AssignWithWriteBarrier(&ht->pointers[ht->bits.keys_offset], ptr);
482 }
483
484 CF_INLINE void *__CFBasicHashGetCounts(CFConstBasicHashRef ht) {
485 return (void *)ht->pointers[ht->bits.counts_offset];
486 }
487
488 CF_INLINE void __CFBasicHashSetCounts(CFBasicHashRef ht, void *ptr) {
489 __AssignWithWriteBarrier(&ht->pointers[ht->bits.counts_offset], ptr);
490 }
491
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;
496 return val;
497 }
498
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;
502 if (!literal) {
503 if (0UL == stack_value) stack_value = __CFBasicHashSubABZero;
504 if (~0UL == stack_value) stack_value = __CFBasicHashSubABOne;
505 }
506 if (CFBasicHashHasStrongValues(ht)) valuep->strong = (id)stack_value; else valuep->neutral = stack_value;
507 if (!ignoreOld) {
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);
512 }
513 }
514 }
515
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;
521 return key;
522 }
523 if (ht->bits.indirect_keys) {
524 uintptr_t stack_value = __CFBasicHashGetValue(ht, idx);
525 return __CFBasicHashGetIndirectKey(ht, stack_value);
526 }
527 return __CFBasicHashGetValue(ht, idx);
528 }
529
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;
534 if (!literal) {
535 if (0UL == stack_key) stack_key = __CFBasicHashSubABZero;
536 if (~0UL == stack_key) stack_key = __CFBasicHashSubABOne;
537 }
538 if (CFBasicHashHasStrongKeys(ht)) keyp->strong = (id)stack_key; else keyp->neutral = stack_key;
539 if (!ignoreOld) {
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);
544 }
545 }
546 }
547
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);
551 }
552
553 CF_INLINE uintptr_t __CFBasicHashIsDeleted(CFConstBasicHashRef ht, CFIndex idx) {
554 uintptr_t stack_value = __CFBasicHashGetValues(ht)[idx].neutral;
555 return (~0UL == stack_value);
556 }
557
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];
565 }
566 return 0;
567 }
568
569 CF_INLINE void __CFBasicHashBumpCounts(CFBasicHashRef ht) {
570 void *counts = __CFBasicHashGetCounts(ht);
571 CFAllocatorRef allocator = CFGetAllocator(ht);
572 switch (ht->bits.counts_width) {
573 case 0: {
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);
578 if (!counts16) HALT;
579 __SetLastAllocationEventName(counts16, "CFBasicHash (count-store)");
580 for (CFIndex idx2 = 0; idx2 < num_buckets; idx2++) {
581 counts16[idx2] = counts08[idx2];
582 }
583 __CFBasicHashSetCounts(ht, counts16);
584 if (!CF_IS_COLLECTABLE_ALLOCATOR(allocator)) {
585 CFAllocatorDeallocate(allocator, counts08);
586 }
587 break;
588 }
589 case 1: {
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);
594 if (!counts32) HALT;
595 __SetLastAllocationEventName(counts32, "CFBasicHash (count-store)");
596 for (CFIndex idx2 = 0; idx2 < num_buckets; idx2++) {
597 counts32[idx2] = counts16[idx2];
598 }
599 __CFBasicHashSetCounts(ht, counts32);
600 if (!CF_IS_COLLECTABLE_ALLOCATOR(allocator)) {
601 CFAllocatorDeallocate(allocator, counts16);
602 }
603 break;
604 }
605 case 2: {
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);
610 if (!counts64) HALT;
611 __SetLastAllocationEventName(counts64, "CFBasicHash (count-store)");
612 for (CFIndex idx2 = 0; idx2 < num_buckets; idx2++) {
613 counts64[idx2] = counts32[idx2];
614 }
615 __CFBasicHashSetCounts(ht, counts64);
616 if (!CF_IS_COLLECTABLE_ALLOCATOR(allocator)) {
617 CFAllocatorDeallocate(allocator, counts32);
618 }
619 break;
620 }
621 case 3: {
622 HALT;
623 break;
624 }
625 }
626 }
627
628 static void __CFBasicHashIncSlotCount(CFBasicHashRef ht, CFIndex idx) {
629 void *counts = __CFBasicHashGetCounts(ht);
630 switch (ht->bits.counts_width) {
631 case 0: {
632 uint8_t *counts08 = (uint8_t *)counts;
633 uint8_t val = counts08[idx];
634 if (val < INT8_MAX) {
635 counts08[idx] = val + 1;
636 return;
637 }
638 __CFBasicHashBumpCounts(ht);
639 __CFBasicHashIncSlotCount(ht, idx);
640 break;
641 }
642 case 1: {
643 uint16_t *counts16 = (uint16_t *)counts;
644 uint16_t val = counts16[idx];
645 if (val < INT16_MAX) {
646 counts16[idx] = val + 1;
647 return;
648 }
649 __CFBasicHashBumpCounts(ht);
650 __CFBasicHashIncSlotCount(ht, idx);
651 break;
652 }
653 case 2: {
654 uint32_t *counts32 = (uint32_t *)counts;
655 uint32_t val = counts32[idx];
656 if (val < INT32_MAX) {
657 counts32[idx] = val + 1;
658 return;
659 }
660 __CFBasicHashBumpCounts(ht);
661 __CFBasicHashIncSlotCount(ht, idx);
662 break;
663 }
664 case 3: {
665 uint64_t *counts64 = (uint64_t *)counts;
666 uint64_t val = counts64[idx];
667 if (val < INT64_MAX) {
668 counts64[idx] = val + 1;
669 return;
670 }
671 __CFBasicHashBumpCounts(ht);
672 __CFBasicHashIncSlotCount(ht, idx);
673 break;
674 }
675 }
676 }
677
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;
685 }
686 }
687
688 CF_INLINE uintptr_t *__CFBasicHashGetHashes(CFConstBasicHashRef ht) {
689 return (uintptr_t *)ht->pointers[ht->bits.hashes_offset];
690 }
691
692 CF_INLINE void __CFBasicHashSetHashes(CFBasicHashRef ht, uintptr_t *ptr) {
693 __AssignWithWriteBarrier(&ht->pointers[ht->bits.hashes_offset], ptr);
694 }
695
696
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];
700 }
701
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;
705 }
706 HALT;
707 return 0;
708 }
709
710 CF_PRIVATE CFIndex CFBasicHashGetNumBuckets(CFConstBasicHashRef ht) {
711 return __CFBasicHashTableSizes[ht->bits.num_buckets_idx];
712 }
713
714 CF_PRIVATE CFIndex CFBasicHashGetCapacity(CFConstBasicHashRef ht) {
715 return __CFBasicHashGetCapacityForNumBuckets(ht, ht->bits.num_buckets_idx);
716 }
717
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
722 // are the same.
723 CF_PRIVATE CFBasicHashBucket CFBasicHashGetBucket(CFConstBasicHashRef ht, CFIndex idx) {
724 CFBasicHashBucket result;
725 result.idx = idx;
726 if (__CFBasicHashIsEmptyOrDeleted(ht, idx)) {
727 result.count = 0;
728 result.weak_value = 0;
729 result.weak_key = 0;
730 } else {
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);
734 }
735 return result;
736 }
737
738 #if defined(__arm__)
739 static uintptr_t __CFBasicHashFold(uintptr_t dividend, uint8_t idx) {
740 switch (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;
780 }
781 HALT;
782 return ~0;
783 }
784 #endif
785
786
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"
792
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"
798
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"
804
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"
810
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"
816
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"
822
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"
828
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"
834
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"
840
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"
846
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"
852
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"
858
859
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};
863 return result;
864 }
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);
870 }
871 } else {
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);
876 }
877 }
878 HALT;
879 CFBasicHashBucket result = {kCFNotFound, 0UL, 0UL, 0};
880 return result;
881 }
882
883 CF_INLINE CFIndex __CFBasicHashFindBucket_NoCollision(CFConstBasicHashRef ht, uintptr_t stack_key, uintptr_t key_hash) {
884 if (0 == ht->bits.num_buckets_idx) {
885 return kCFNotFound;
886 }
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);
892 }
893 } else {
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);
898 }
899 }
900 HALT;
901 return kCFNotFound;
902 }
903
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};
907 return result;
908 }
909 return __CFBasicHashFindBucket(ht, stack_key);
910 }
911
912 CF_PRIVATE void CFBasicHashSuppressRC(CFBasicHashRef ht) {
913 ht->bits.null_rc = 1;
914 }
915
916 CF_PRIVATE void CFBasicHashUnsuppressRC(CFBasicHashRef ht) {
917 ht->bits.null_rc = 0;
918 }
919
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;
928 return flags;
929 }
930
931 CF_PRIVATE CFIndex CFBasicHashGetCount(CFConstBasicHashRef ht) {
932 if (ht->bits.counts_offset) {
933 CFIndex total = 0L;
934 CFIndex cnt = (CFIndex)__CFBasicHashTableSizes[ht->bits.num_buckets_idx];
935 for (CFIndex idx = 0; idx < cnt; idx++) {
936 total += __CFBasicHashGetSlotCount(ht, idx);
937 }
938 return total;
939 }
940 return (CFIndex)ht->bits.used_buckets;
941 }
942
943 CF_PRIVATE CFIndex CFBasicHashGetCountOfKey(CFConstBasicHashRef ht, uintptr_t stack_key) {
944 if (__CFBasicHashSubABZero == stack_key || __CFBasicHashSubABOne == stack_key) {
945 return 0L;
946 }
947 if (0L == ht->bits.used_buckets) {
948 return 0L;
949 }
950 return __CFBasicHashFindBucket(ht, stack_key).count;
951 }
952
953 CF_PRIVATE CFIndex CFBasicHashGetCountOfValue(CFConstBasicHashRef ht, uintptr_t stack_value) {
954 if (__CFBasicHashSubABZero == stack_value) {
955 return 0L;
956 }
957 if (0L == ht->bits.used_buckets) {
958 return 0L;
959 }
960 if (!(ht->bits.keys_offset)) {
961 return __CFBasicHashFindBucket(ht, stack_value).count;
962 }
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;
967 });
968 return total;
969 }
970
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) {
979 equal = false;
980 return (Boolean)false;
981 }
982 if ((ht1->bits.keys_offset) && (bkt1.weak_value != bkt2.weak_value) && !__CFBasicHashTestEqualValue(ht1, bkt1.weak_value, bkt2.weak_value)) {
983 equal = false;
984 return (Boolean)false;
985 }
986 return (Boolean)true;
987 });
988 return equal;
989 }
990
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);
995 if (0 < bkt.count) {
996 if (!block(bkt)) {
997 return;
998 }
999 used--;
1000 }
1001 }
1002 }
1003
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) {
1012 if (!block(bkt)) {
1013 return;
1014 }
1015 }
1016 }
1017 }
1018
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];
1021 CFIndex offset = 0;
1022 for (CFIndex idx = 0; 0 < used && idx < cnt && offset < bufferslen; idx++) {
1023 CFBasicHashBucket bkt = CFBasicHashGetBucket(ht, idx);
1024 if (0 < bkt.count) {
1025 used--;
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; }
1029 offset++;
1030 }
1031 }
1032 }
1033 }
1034
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;
1039 }
1040 state->itemsPtr = (unsigned long *)stackbuffer;
1041 CFIndex cntx = 0;
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;
1047 used--;
1048 }
1049 state->state++;
1050 }
1051 return cntx;
1052 }
1053
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};
1060 #endif
1061
1062 static void __CFBasicHashDrain(CFBasicHashRef ht, Boolean forFinalization) {
1063 #if ENABLE_MEMORY_COUNTERS
1064 OSAtomicAdd64Barrier(-1 * (int64_t) CFBasicHashGetSize(ht, true), & __CFBasicHashTotalSize);
1065 #endif
1066
1067 CFIndex old_num_buckets = __CFBasicHashTableSizes[ht->bits.num_buckets_idx];
1068
1069 CFAllocatorRef allocator = CFGetAllocator(ht);
1070 Boolean nullify = (!forFinalization || !CF_IS_COLLECTABLE_ALLOCATOR(allocator));
1071
1072 CFBasicHashValue *old_values = NULL, *old_keys = NULL;
1073 void *old_counts = NULL;
1074 uintptr_t *old_hashes = NULL;
1075
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);
1081 }
1082 if (ht->bits.counts_offset) {
1083 old_counts = __CFBasicHashGetCounts(ht);
1084 if (nullify) __CFBasicHashSetCounts(ht, NULL);
1085 }
1086 if (__CFBasicHashHasHashCache(ht)) {
1087 old_hashes = __CFBasicHashGetHashes(ht);
1088 if (nullify) __CFBasicHashSetHashes(ht, NULL);
1089 }
1090
1091 if (nullify) {
1092 ht->bits.mutations++;
1093 ht->bits.num_buckets_idx = 0;
1094 ht->bits.used_buckets = 0;
1095 ht->bits.deleted = 0;
1096 }
1097
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);
1105 if (old_keys) {
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);
1110 }
1111 }
1112 }
1113
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);
1119 }
1120
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));
1124 #endif
1125 }
1126
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]);
1131 #endif
1132
1133 if (COCOA_HASHTABLE_REHASH_START_ENABLED()) COCOA_HASHTABLE_REHASH_START(ht, CFBasicHashGetNumBuckets(ht), CFBasicHashGetSize(ht, true));
1134
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++;
1142 }
1143 }
1144
1145 CFIndex new_num_buckets = __CFBasicHashTableSizes[new_num_buckets_idx];
1146 CFIndex old_num_buckets = __CFBasicHashTableSizes[ht->bits.num_buckets_idx];
1147
1148 CFBasicHashValue *new_values = NULL, *new_keys = NULL;
1149 void *new_counts = NULL;
1150 uintptr_t *new_hashes = NULL;
1151
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));
1162 }
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));
1168 }
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));
1174 }
1175 }
1176
1177 ht->bits.num_buckets_idx = new_num_buckets_idx;
1178 ht->bits.deleted = 0;
1179
1180 CFBasicHashValue *old_values = NULL, *old_keys = NULL;
1181 void *old_counts = NULL;
1182 uintptr_t *old_hashes = NULL;
1183
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);
1189 }
1190 if (ht->bits.counts_offset) {
1191 old_counts = __CFBasicHashGetCounts(ht);
1192 __CFBasicHashSetCounts(ht, new_counts);
1193 }
1194 if (__CFBasicHashHasHashCache(ht)) {
1195 old_hashes = __CFBasicHashGetHashes(ht);
1196 __CFBasicHashSetHashes(ht, new_hashes);
1197 }
1198
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;
1210 }
1211 if (ht->bits.indirect_keys) {
1212 stack_key = __CFBasicHashGetIndirectKey(ht, stack_value);
1213 }
1214 CFIndex bkt_idx = __CFBasicHashFindBucket_NoCollision(ht, stack_key, old_hashes ? old_hashes[idx] : 0UL);
1215 __CFBasicHashSetValue(ht, bkt_idx, stack_value, false, false);
1216 if (old_keys) {
1217 __CFBasicHashSetKey(ht, bkt_idx, stack_key, false, false);
1218 }
1219 if (old_counts) {
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;
1225 }
1226 }
1227 if (old_hashes) {
1228 new_hashes[bkt_idx] = old_hashes[idx];
1229 }
1230 }
1231 }
1232 }
1233
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);
1240 }
1241
1242 if (COCOA_HASHTABLE_REHASH_END_ENABLED()) COCOA_HASHTABLE_REHASH_END(ht, CFBasicHashGetNumBuckets(ht), CFBasicHashGetSize(ht, true));
1243
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]);
1248 #endif
1249 }
1250
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);
1256 }
1257 }
1258
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)) {
1265 ht->bits.deleted--;
1266 }
1267 uintptr_t key_hash = 0;
1268 if (__CFBasicHashHasHashCache(ht)) {
1269 key_hash = __CFBasicHashHashKey(ht, stack_key);
1270 }
1271 stack_value = __CFBasicHashImportValue(ht, stack_value);
1272 if (ht->bits.keys_offset) {
1273 stack_key = __CFBasicHashImportKey(ht, stack_key);
1274 }
1275 __CFBasicHashSetValue(ht, bkt_idx, stack_value, false, false);
1276 if (ht->bits.keys_offset) {
1277 __CFBasicHashSetKey(ht, bkt_idx, stack_key, false, false);
1278 }
1279 if (ht->bits.counts_offset) {
1280 __CFBasicHashIncSlotCount(ht, bkt_idx);
1281 }
1282 if (__CFBasicHashHasHashCache(ht)) {
1283 __CFBasicHashGetHashes(ht)[bkt_idx] = key_hash;
1284 }
1285 ht->bits.used_buckets++;
1286 }
1287
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);
1293 }
1294 __CFBasicHashSetValue(ht, bkt_idx, stack_value, false, false);
1295 if (ht->bits.keys_offset) {
1296 __CFBasicHashSetKey(ht, bkt_idx, stack_key, false, false);
1297 }
1298 }
1299
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);
1305 }
1306 if (ht->bits.counts_offset) {
1307 __CFBasicHashDecSlotCount(ht, bkt_idx);
1308 }
1309 if (__CFBasicHashHasHashCache(ht)) {
1310 __CFBasicHashGetHashes(ht)[bkt_idx] = 0;
1311 }
1312 ht->bits.used_buckets--;
1313 ht->bits.deleted++;
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));
1317 } else {
1318 do_shrink = (2 < ht->bits.num_buckets_idx && ht->bits.used_buckets < __CFBasicHashGetCapacityForNumBuckets(ht, ht->bits.num_buckets_idx - 2));
1319 }
1320 if (do_shrink) {
1321 __CFBasicHashRehash(ht, -1);
1322 return;
1323 }
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));
1327 if (do_shrink) {
1328 __CFBasicHashRehash(ht, 0);
1329 }
1330 }
1331
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);
1343 return true;
1344 }
1345 } else {
1346 __CFBasicHashAddValue(ht, bkt.idx, stack_key, stack_value);
1347 return true;
1348 }
1349 return false;
1350 }
1351
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);
1361 }
1362 }
1363
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);
1373 } else {
1374 __CFBasicHashAddValue(ht, bkt.idx, stack_key, stack_value);
1375 }
1376 }
1377
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);
1386 }
1387 } else if (0 < bkt.count) {
1388 __CFBasicHashRemoveValue(ht, bkt.idx);
1389 }
1390 return bkt.count;
1391 }
1392
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);
1400 }
1401 } else if (0 < bkt.count) {
1402 __CFBasicHashRemoveValue(ht, bkt.idx);
1403 }
1404 return bkt.count;
1405 }
1406
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);
1411 }
1412
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++;
1422 } else {
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);
1427 }
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) {
1433 stack_value++;
1434 __CFBasicHashSetValue(ht, idx, stack_value, true, false);
1435 ht->bits.mutations++;
1436 }
1437 }
1438 }
1439 __CFBasicHashAddValue(ht, bkt.idx, stack_key, int_value);
1440 return true;
1441 }
1442 return false;
1443 }
1444
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) {
1455 bkt_idx = idx;
1456 }
1457 if (int_value < stack_value) {
1458 stack_value--;
1459 __CFBasicHashSetValue(ht, idx, stack_value, true, false);
1460 ht->bits.mutations++;
1461 }
1462 }
1463 }
1464 __CFBasicHashRemoveValue(ht, bkt_idx);
1465 }
1466
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 *);
1472 if (total) {
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));
1479 }
1480 }
1481 return size;
1482 }
1483
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));
1487 if (detailed) {
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));
1494 }
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);
1502 }
1503 } else {
1504 vDesc = __CFBasicHashDescValue(ht, bkt.weak_value);
1505 if (ht->bits.keys_offset) {
1506 kDesc = __CFBasicHashDescKey(ht, bkt.weak_key);
1507 }
1508 }
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);
1515 } else {
1516 CFStringAppendFormat(result, NULL, CFSTR("%@%ld : %@\n"), entryPrefix, bkt.idx, vDesc);
1517 }
1518 if (kDesc) CFRelease(kDesc);
1519 if (vDesc) CFRelease(vDesc);
1520 return (Boolean)true;
1521 });
1522 CFStringAppendFormat(result, NULL, CFSTR("%@}\n"), prefix);
1523 return result;
1524 }
1525
1526 CF_PRIVATE void CFBasicHashShow(CFConstBasicHashRef ht) {
1527 CFStringRef str = CFBasicHashCopyDescription(ht, true, CFSTR(""), CFSTR("\t"), false);
1528 CFShow(str);
1529 CFRelease(str);
1530 }
1531
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);
1537 }
1538
1539 CF_PRIVATE CFHashCode __CFBasicHashHash(CFTypeRef cf) {
1540 CFBasicHashRef ht = (CFBasicHashRef)cf;
1541 return CFBasicHashGetCount(ht);
1542 }
1543
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);
1548 CFRelease(desc);
1549 return result;
1550 }
1551
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]);
1560 #endif
1561 }
1562
1563 static CFTypeID __kCFBasicHashTypeID = _kCFRuntimeNotATypeID;
1564
1565 static const CFRuntimeClass __CFBasicHashClass = {
1566 _kCFRuntimeScannedObject,
1567 "CFBasicHash",
1568 NULL, // init
1569 NULL, // copy
1570 __CFBasicHashDeallocate,
1571 __CFBasicHashEqual,
1572 __CFBasicHashHash,
1573 NULL, //
1574 __CFBasicHashCopyDescription
1575 };
1576
1577 CF_PRIVATE CFTypeID CFBasicHashGetTypeID(void) {
1578 static dispatch_once_t initOnce;
1579 dispatch_once(&initOnce, ^{ __kCFBasicHashTypeID = _CFRuntimeRegisterClass(&__CFBasicHashClass); });
1580 return __kCFBasicHashTypeID;
1581 }
1582
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;
1590
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;
1606
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;
1616
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;
1621
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;
1628 #endif
1629
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);
1640
1641 for (CFIndex idx = 0; idx < offset; idx++) {
1642 ht->pointers[idx] = NULL;
1643 }
1644
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]);
1651 #endif
1652
1653 return ht;
1654 }
1655
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;
1662
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)");
1673 }
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)");
1678 }
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)");
1683 }
1684 }
1685
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
1688
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;
1695 }
1696 ht->bits.finalized = 0;
1697 ht->bits.mutations = 1;
1698
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]);
1706 #endif
1707 return ht;
1708 }
1709
1710 CFBasicHashValue *old_values = NULL, *old_keys = NULL;
1711 void *old_counts = NULL;
1712 uintptr_t *old_hashes = NULL;
1713
1714 old_values = __CFBasicHashGetValues(src_ht);
1715 if (src_ht->bits.keys_offset) {
1716 old_keys = __CFBasicHashGetKeys(src_ht);
1717 }
1718 if (src_ht->bits.counts_offset) {
1719 old_counts = __CFBasicHashGetCounts(src_ht);
1720 }
1721 if (__CFBasicHashHasHashCache(src_ht)) {
1722 old_hashes = __CFBasicHashGetHashes(src_ht);
1723 }
1724
1725 __CFBasicHashSetValues(ht, new_values);
1726 if (new_keys) {
1727 __CFBasicHashSetKeys(ht, new_keys);
1728 }
1729 if (new_counts) {
1730 __CFBasicHashSetCounts(ht, new_counts);
1731 }
1732 if (new_hashes) {
1733 __CFBasicHashSetHashes(ht, new_hashes);
1734 }
1735
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);
1743 if (new_keys) {
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);
1748 }
1749 } else {
1750 __CFBasicHashSetValue(ht, idx, stack_value, true, true);
1751 if (new_keys) {
1752 __CFBasicHashSetKey(ht, idx, stack_value, true, true);
1753 }
1754 }
1755 }
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));
1758
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]);
1765 #endif
1766
1767 return ht;
1768 }
1769
1770