]> git.saurik.com Git - apple/cf.git/blob - CFBasicHash.m
CF-550.19.tar.gz
[apple/cf.git] / CFBasicHash.m
1 /*
2 * Copyright (c) 2010 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-2009, 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 <objc/objc.h>
34 #import <math.h>
35
36 #if DEPLOYMENT_TARGET_WINDOWS
37 #define __SetLastAllocationEventName(A, B) do { } while (0)
38 #else
39 #define __SetLastAllocationEventName(A, B) do { if (__CFOASafe && (A)) __CFSetLastAllocationEventName(A, B); } while (0)
40 #endif
41
42 #define GCRETAIN(A, B) kCFTypeSetCallBacks.retain(A, B)
43 #define GCRELEASE(A, B) kCFTypeSetCallBacks.release(A, B)
44
45 #define __AssignWithWriteBarrier(location, value) objc_assign_strongCast((id)value, (id *)location)
46
47 #define ENABLE_DTRACE_PROBES 0
48 #define ENABLE_MEMORY_COUNTERS 0
49
50
51 /*
52 // dtrace -h -s foo.d
53 // Note: output then changed by putting do/while around macro bodies and adding a cast of the arguments
54
55 provider Cocoa_HashTable {
56 probe hash_key(unsigned long table, unsigned long key, unsigned long hash);
57 probe test_equal(unsigned long table, unsigned long key1, unsigned long key2);
58 probe probing_start(unsigned long table, unsigned long num_buckets);
59 probe probe_empty(unsigned long table, unsigned long idx);
60 probe probe_deleted(unsigned long table, unsigned long idx);
61 probe probe_valid(unsigned long table, unsigned long idx);
62 probe probing_end(unsigned long table, unsigned long num_probes);
63 probe rehash_start(unsigned long table, unsigned long num_buckets, unsigned long total_size);
64 probe rehash_end(unsigned long table, unsigned long num_buckets, unsigned long total_size);
65 };
66
67 #pragma D attributes Unstable/Unstable/Common provider Cocoa_HashTable provider
68 #pragma D attributes Private/Private/Unknown provider Cocoa_HashTable module
69 #pragma D attributes Private/Private/Unknown provider Cocoa_HashTable function
70 #pragma D attributes Unstable/Unstable/Common provider Cocoa_HashTable name
71 #pragma D attributes Unstable/Unstable/Common provider Cocoa_HashTable args
72 */
73
74 #if ENABLE_DTRACE_PROBES
75
76 #define COCOA_HASHTABLE_STABILITY "___dtrace_stability$Cocoa_HashTable$v1$4_4_5_1_1_0_1_1_0_4_4_5_4_4_5"
77
78 #define COCOA_HASHTABLE_TYPEDEFS "___dtrace_typedefs$Cocoa_HashTable$v2"
79
80 #define COCOA_HASHTABLE_REHASH_END(arg0, arg1, arg2) \
81 do { \
82 __asm__ volatile(".reference " COCOA_HASHTABLE_TYPEDEFS); \
83 __dtrace_probe$Cocoa_HashTable$rehash_end$v1$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67((unsigned long)(arg0), (unsigned long)(arg1), (unsigned long)(arg2)); \
84 __asm__ volatile(".reference " COCOA_HASHTABLE_STABILITY); \
85 } while (0)
86 #define COCOA_HASHTABLE_REHASH_END_ENABLED() \
87 __dtrace_isenabled$Cocoa_HashTable$rehash_end$v1()
88 #define COCOA_HASHTABLE_REHASH_START(arg0, arg1, arg2) \
89 do { \
90 __asm__ volatile(".reference " COCOA_HASHTABLE_TYPEDEFS); \
91 __dtrace_probe$Cocoa_HashTable$rehash_start$v1$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67((unsigned long)(arg0), (unsigned long)(arg1), (unsigned long)(arg2)); \
92 __asm__ volatile(".reference " COCOA_HASHTABLE_STABILITY); \
93 } while (0)
94 #define COCOA_HASHTABLE_REHASH_START_ENABLED() \
95 __dtrace_isenabled$Cocoa_HashTable$rehash_start$v1()
96 #define COCOA_HASHTABLE_HASH_KEY(arg0, arg1, arg2) \
97 do { \
98 __asm__ volatile(".reference " COCOA_HASHTABLE_TYPEDEFS); \
99 __dtrace_probe$Cocoa_HashTable$hash_key$v1$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67((unsigned long)(arg0), (unsigned long)(arg1), (unsigned long)(arg2)); \
100 __asm__ volatile(".reference " COCOA_HASHTABLE_STABILITY); \
101 } while (0)
102 #define COCOA_HASHTABLE_HASH_KEY_ENABLED() \
103 __dtrace_isenabled$Cocoa_HashTable$hash_key$v1()
104 #define COCOA_HASHTABLE_PROBE_DELETED(arg0, arg1) \
105 do { \
106 __asm__ volatile(".reference " COCOA_HASHTABLE_TYPEDEFS); \
107 __dtrace_probe$Cocoa_HashTable$probe_deleted$v1$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67((unsigned long)(arg0), (unsigned long)(arg1)); \
108 __asm__ volatile(".reference " COCOA_HASHTABLE_STABILITY); \
109 } while (0)
110 #define COCOA_HASHTABLE_PROBE_DELETED_ENABLED() \
111 __dtrace_isenabled$Cocoa_HashTable$probe_deleted$v1()
112 #define COCOA_HASHTABLE_PROBE_EMPTY(arg0, arg1) \
113 do { \
114 __asm__ volatile(".reference " COCOA_HASHTABLE_TYPEDEFS); \
115 __dtrace_probe$Cocoa_HashTable$probe_empty$v1$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67((unsigned long)(arg0), (unsigned long)(arg1)); \
116 __asm__ volatile(".reference " COCOA_HASHTABLE_STABILITY); \
117 } while (0)
118 #define COCOA_HASHTABLE_PROBE_EMPTY_ENABLED() \
119 __dtrace_isenabled$Cocoa_HashTable$probe_empty$v1()
120 #define COCOA_HASHTABLE_PROBE_VALID(arg0, arg1) \
121 do { \
122 __asm__ volatile(".reference " COCOA_HASHTABLE_TYPEDEFS); \
123 __dtrace_probe$Cocoa_HashTable$probe_valid$v1$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67((unsigned long)(arg0), (unsigned long)(arg1)); \
124 __asm__ volatile(".reference " COCOA_HASHTABLE_STABILITY); \
125 } while (0)
126 #define COCOA_HASHTABLE_PROBE_VALID_ENABLED() \
127 __dtrace_isenabled$Cocoa_HashTable$probe_valid$v1()
128 #define COCOA_HASHTABLE_PROBING_END(arg0, arg1) \
129 do { \
130 __asm__ volatile(".reference " COCOA_HASHTABLE_TYPEDEFS); \
131 __dtrace_probe$Cocoa_HashTable$probing_end$v1$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67((unsigned long)(arg0), (unsigned long)(arg1)); \
132 __asm__ volatile(".reference " COCOA_HASHTABLE_STABILITY); \
133 } while (0)
134 #define COCOA_HASHTABLE_PROBING_END_ENABLED() \
135 __dtrace_isenabled$Cocoa_HashTable$probing_end$v1()
136 #define COCOA_HASHTABLE_PROBING_START(arg0, arg1) \
137 do { \
138 __asm__ volatile(".reference " COCOA_HASHTABLE_TYPEDEFS); \
139 __dtrace_probe$Cocoa_HashTable$probing_start$v1$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67((unsigned long)(arg0), (unsigned long)(arg1)); \
140 __asm__ volatile(".reference " COCOA_HASHTABLE_STABILITY); \
141 } while (0)
142 #define COCOA_HASHTABLE_PROBING_START_ENABLED() \
143 __dtrace_isenabled$Cocoa_HashTable$probing_start$v1()
144 #define COCOA_HASHTABLE_TEST_EQUAL(arg0, arg1, arg2) \
145 do { \
146 __asm__ volatile(".reference " COCOA_HASHTABLE_TYPEDEFS); \
147 __dtrace_probe$Cocoa_HashTable$test_equal$v1$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67((unsigned long)(arg0), (unsigned long)(arg1), (unsigned long)(arg2)); \
148 __asm__ volatile(".reference " COCOA_HASHTABLE_STABILITY); \
149 } while (0)
150 #define COCOA_HASHTABLE_TEST_EQUAL_ENABLED() \
151 __dtrace_isenabled$Cocoa_HashTable$test_equal$v1()
152
153 extern void __dtrace_probe$Cocoa_HashTable$rehash_end$v1$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67(unsigned long, unsigned long, unsigned long);
154 extern int __dtrace_isenabled$Cocoa_HashTable$rehash_end$v1(void);
155 extern void __dtrace_probe$Cocoa_HashTable$rehash_start$v1$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67(unsigned long, unsigned long, unsigned long);
156 extern int __dtrace_isenabled$Cocoa_HashTable$rehash_start$v1(void);
157 extern void __dtrace_probe$Cocoa_HashTable$hash_key$v1$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67(unsigned long, unsigned long, unsigned long);
158 extern int __dtrace_isenabled$Cocoa_HashTable$hash_key$v1(void);
159 extern void __dtrace_probe$Cocoa_HashTable$probe_deleted$v1$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67(unsigned long, unsigned long);
160 extern int __dtrace_isenabled$Cocoa_HashTable$probe_deleted$v1(void);
161 extern void __dtrace_probe$Cocoa_HashTable$probe_empty$v1$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67(unsigned long, unsigned long);
162 extern int __dtrace_isenabled$Cocoa_HashTable$probe_empty$v1(void);
163 extern void __dtrace_probe$Cocoa_HashTable$probe_valid$v1$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67(unsigned long, unsigned long);
164 extern int __dtrace_isenabled$Cocoa_HashTable$probe_valid$v1(void);
165 extern void __dtrace_probe$Cocoa_HashTable$probing_end$v1$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67(unsigned long, unsigned long);
166 extern int __dtrace_isenabled$Cocoa_HashTable$probing_end$v1(void);
167 extern void __dtrace_probe$Cocoa_HashTable$probing_start$v1$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67(unsigned long, unsigned long);
168 extern int __dtrace_isenabled$Cocoa_HashTable$probing_start$v1(void);
169 extern void __dtrace_probe$Cocoa_HashTable$test_equal$v1$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67(unsigned long, unsigned long, unsigned long);
170 extern int __dtrace_isenabled$Cocoa_HashTable$test_equal$v1(void);
171
172 #else
173
174 #define COCOA_HASHTABLE_REHASH_END(arg0, arg1, arg2) do {} while (0)
175 #define COCOA_HASHTABLE_REHASH_END_ENABLED() 0
176 #define COCOA_HASHTABLE_REHASH_START(arg0, arg1, arg2) do {} while (0)
177 #define COCOA_HASHTABLE_REHASH_START_ENABLED() 0
178 #define COCOA_HASHTABLE_HASH_KEY(arg0, arg1, arg2) do {} while (0)
179 #define COCOA_HASHTABLE_HASH_KEY_ENABLED() 0
180 #define COCOA_HASHTABLE_PROBE_DELETED(arg0, arg1) do {} while (0)
181 #define COCOA_HASHTABLE_PROBE_DELETED_ENABLED() 0
182 #define COCOA_HASHTABLE_PROBE_EMPTY(arg0, arg1) do {} while (0)
183 #define COCOA_HASHTABLE_PROBE_EMPTY_ENABLED() 0
184 #define COCOA_HASHTABLE_PROBE_VALID(arg0, arg1) do {} while (0)
185 #define COCOA_HASHTABLE_PROBE_VALID_ENABLED() 0
186 #define COCOA_HASHTABLE_PROBING_END(arg0, arg1) do {} while (0)
187 #define COCOA_HASHTABLE_PROBING_END_ENABLED() 0
188 #define COCOA_HASHTABLE_PROBING_START(arg0, arg1) do {} while (0)
189 #define COCOA_HASHTABLE_PROBING_START_ENABLED() 0
190 #define COCOA_HASHTABLE_TEST_EQUAL(arg0, arg1, arg2) do {} while (0)
191 #define COCOA_HASHTABLE_TEST_EQUAL_ENABLED() 0
192
193 #endif
194
195
196 #if !defined(__LP64__)
197 #define __LP64__ 0
198 #endif
199
200 enum {
201 #if __LP64__
202 __CFBasicHashMarkerShift = 40 // 64 - 24
203 #else
204 __CFBasicHashMarkerShift = 8 // 32 - 24
205 #endif
206 };
207
208 typedef union {
209 uintptr_t weak;
210 id strong;
211 } CFBasicHashValue;
212
213 struct __CFBasicHash {
214 CFRuntimeBase base;
215 struct { // 128 bits
216 uint64_t hash_style:2;
217 uint64_t values2_offset:1;
218 uint64_t keys_offset:2;
219 uint64_t keys2_offset:2;
220 uint64_t counts_offset:3;
221 uint64_t orders_offset:3;
222 uint64_t hashes_offset:3;
223 uint64_t num_buckets_idx:6; /* index to number of buckets */
224 uint64_t used_buckets:42; /* number of used buckets */
225 uint64_t __0:2;
226 uint64_t finalized:1;
227 uint64_t fast_grow:1;
228 uint64_t strong_values:1;
229 uint64_t strong_values2:1;
230 uint64_t strong_keys:1;
231 uint64_t strong_keys2:1;
232 uint64_t marker:24;
233 uint64_t deleted:16;
234 uint64_t mutations:16;
235 } bits;
236 __strong const CFBasicHashCallbacks *callbacks;
237 void *pointers[1];
238 };
239
240 CF_INLINE CFBasicHashValue *__CFBasicHashGetValues(CFBasicHashRef ht) {
241 return (CFBasicHashValue *)ht->pointers[0];
242 }
243
244 CF_INLINE void __CFBasicHashSetValues(CFBasicHashRef ht, CFBasicHashValue *ptr) {
245 __AssignWithWriteBarrier(&ht->pointers[0], ptr);
246 }
247
248 CF_INLINE CFBasicHashValue *__CFBasicHashGetValues2(CFBasicHashRef ht) {
249 if (0 == ht->bits.values2_offset) HALT;
250 return (CFBasicHashValue *)ht->pointers[ht->bits.values2_offset];
251 }
252
253 CF_INLINE void __CFBasicHashSetValues2(CFBasicHashRef ht, CFBasicHashValue *ptr) {
254 if (0 == ht->bits.values2_offset) HALT;
255 __AssignWithWriteBarrier(&ht->pointers[ht->bits.values2_offset], ptr);
256 }
257
258 CF_INLINE CFBasicHashValue *__CFBasicHashGetKeys(CFBasicHashRef ht) {
259 if (0 == ht->bits.keys_offset) HALT;
260 return (CFBasicHashValue *)ht->pointers[ht->bits.keys_offset];
261 }
262
263 CF_INLINE void __CFBasicHashSetKeys(CFBasicHashRef ht, CFBasicHashValue *ptr) {
264 if (0 == ht->bits.keys_offset) HALT;
265 __AssignWithWriteBarrier(&ht->pointers[ht->bits.keys_offset], ptr);
266 }
267
268 CF_INLINE CFBasicHashValue *__CFBasicHashGetKeys2(CFBasicHashRef ht) {
269 if (0 == ht->bits.keys2_offset) HALT;
270 return (CFBasicHashValue *)ht->pointers[ht->bits.keys2_offset];
271 }
272
273 CF_INLINE void __CFBasicHashSetKeys2(CFBasicHashRef ht, CFBasicHashValue *ptr) {
274 if (0 == ht->bits.keys2_offset) HALT;
275 __AssignWithWriteBarrier(&ht->pointers[ht->bits.keys2_offset], ptr);
276 }
277
278 CF_INLINE uintptr_t *__CFBasicHashGetCounts(CFBasicHashRef ht) {
279 if (0 == ht->bits.counts_offset) HALT;
280 return (uintptr_t *)ht->pointers[ht->bits.counts_offset];
281 }
282
283 CF_INLINE void __CFBasicHashSetCounts(CFBasicHashRef ht, uintptr_t *ptr) {
284 if (0 == ht->bits.counts_offset) HALT;
285 __AssignWithWriteBarrier(&ht->pointers[ht->bits.counts_offset], ptr);
286 }
287
288 CF_INLINE uintptr_t *__CFBasicHashGetOrders(CFBasicHashRef ht) {
289 if (0 == ht->bits.orders_offset) HALT;
290 return (uintptr_t *)ht->pointers[ht->bits.orders_offset];
291 }
292
293 CF_INLINE void __CFBasicHashSetOrders(CFBasicHashRef ht, uintptr_t *ptr) {
294 if (0 == ht->bits.orders_offset) HALT;
295 __AssignWithWriteBarrier(&ht->pointers[ht->bits.orders_offset], ptr);
296 }
297
298 CF_INLINE uintptr_t *__CFBasicHashGetHashes(CFBasicHashRef ht) {
299 if (0 == ht->bits.hashes_offset) HALT;
300 return (uintptr_t *)ht->pointers[ht->bits.hashes_offset];
301 }
302
303 CF_INLINE void __CFBasicHashSetHashes(CFBasicHashRef ht, uintptr_t *ptr) {
304 if (0 == ht->bits.hashes_offset) HALT;
305 __AssignWithWriteBarrier(&ht->pointers[ht->bits.hashes_offset], ptr);
306 }
307
308 static uintptr_t __CFBasicHashNullCallback(CFBasicHashRef ht, uint8_t op, uintptr_t a1, uintptr_t a2, const CFBasicHashCallbacks *cb) {
309 switch (op) {
310 case kCFBasicHashCallbackOpCopyCallbacks: return (uintptr_t)&CFBasicHashNullCallbacks;
311 case kCFBasicHashCallbackOpFreeCallbacks: return 0;
312 case kCFBasicHashCallbackOpRetainValue:
313 case kCFBasicHashCallbackOpRetainValue2:
314 case kCFBasicHashCallbackOpRetainKey:
315 case kCFBasicHashCallbackOpRetainKey2: return a1;
316 case kCFBasicHashCallbackOpReleaseValue:
317 case kCFBasicHashCallbackOpReleaseValue2:
318 case kCFBasicHashCallbackOpReleaseKey:
319 case kCFBasicHashCallbackOpReleaseKey2: return 0;
320 case kCFBasicHashCallbackOpValueEqual:
321 case kCFBasicHashCallbackOpValue2Equal:
322 case kCFBasicHashCallbackOpKeyEqual:
323 case kCFBasicHashCallbackOpKey2Equal: return a1 == a2;
324 case kCFBasicHashCallbackOpHashKey:
325 case kCFBasicHashCallbackOpHashKey2: return a1;
326 case kCFBasicHashCallbackOpDescribeValue:
327 case kCFBasicHashCallbackOpDescribeValue2:
328 case kCFBasicHashCallbackOpDescribeKey:
329 case kCFBasicHashCallbackOpDescribeKey2: return (uintptr_t)CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<%p>"), (void *)a1);
330 }
331 return 0;
332 }
333
334 static uintptr_t __CFBasicHashStandardCallback(CFBasicHashRef ht, uint8_t op, uintptr_t a1, uintptr_t a2, const CFBasicHashCallbacks *cb) {
335 switch (op) {
336 case kCFBasicHashCallbackOpCopyCallbacks: return (uintptr_t)&CFBasicHashStandardCallbacks;
337 case kCFBasicHashCallbackOpFreeCallbacks: return 0;
338 case kCFBasicHashCallbackOpRetainValue: return (ht->bits.strong_values) ? (uintptr_t)GCRETAIN(kCFAllocatorSystemDefault, (CFTypeRef)a1) : (uintptr_t)CFRetain((CFTypeRef)a1);
339 case kCFBasicHashCallbackOpRetainValue2: return (ht->bits.strong_values2) ? (uintptr_t)GCRETAIN(kCFAllocatorSystemDefault, (CFTypeRef)a1) : (uintptr_t)CFRetain((CFTypeRef)a1);
340 case kCFBasicHashCallbackOpRetainKey: return (ht->bits.strong_keys) ? (uintptr_t)GCRETAIN(kCFAllocatorSystemDefault, (CFTypeRef)a1) : (uintptr_t)CFRetain((CFTypeRef)a1);
341 case kCFBasicHashCallbackOpRetainKey2: return (ht->bits.strong_keys2) ? (uintptr_t)GCRETAIN(kCFAllocatorSystemDefault, (CFTypeRef)a1) : (uintptr_t)CFRetain((CFTypeRef)a1);
342 case kCFBasicHashCallbackOpReleaseValue: if (ht->bits.strong_values) GCRELEASE(kCFAllocatorSystemDefault, (CFTypeRef)a1); else CFRelease((CFTypeRef)a1); return 0;
343 case kCFBasicHashCallbackOpReleaseValue2: if (ht->bits.strong_values2) GCRELEASE(kCFAllocatorSystemDefault, (CFTypeRef)a1); else CFRelease((CFTypeRef)a1); return 0;
344 case kCFBasicHashCallbackOpReleaseKey: if (ht->bits.strong_keys) GCRELEASE(kCFAllocatorSystemDefault, (CFTypeRef)a1); else CFRelease((CFTypeRef)a1); return 0;
345 case kCFBasicHashCallbackOpReleaseKey2: if (ht->bits.strong_keys2) GCRELEASE(kCFAllocatorSystemDefault, (CFTypeRef)a1); else CFRelease((CFTypeRef)a1); return 0;
346 case kCFBasicHashCallbackOpValueEqual:
347 case kCFBasicHashCallbackOpValue2Equal:
348 case kCFBasicHashCallbackOpKeyEqual:
349 case kCFBasicHashCallbackOpKey2Equal: return CFEqual((CFTypeRef)a1, (CFTypeRef)a2);
350 case kCFBasicHashCallbackOpHashKey:
351 case kCFBasicHashCallbackOpHashKey2: return (uintptr_t)CFHash((CFTypeRef)a1);
352 case kCFBasicHashCallbackOpDescribeValue:
353 case kCFBasicHashCallbackOpDescribeValue2:
354 case kCFBasicHashCallbackOpDescribeKey:
355 case kCFBasicHashCallbackOpDescribeKey2: return (uintptr_t)CFCopyDescription((CFTypeRef)a1);
356 }
357 return 0;
358 }
359
360 __private_extern__ const CFBasicHashCallbacks CFBasicHashNullCallbacks = {__CFBasicHashNullCallback};
361 __private_extern__ const CFBasicHashCallbacks CFBasicHashStandardCallbacks = {__CFBasicHashStandardCallback};
362
363 CF_INLINE uintptr_t __CFBasicHashImportValue(CFBasicHashRef ht, uintptr_t stack_value) {
364 return ht->callbacks->func(ht, kCFBasicHashCallbackOpRetainValue, stack_value, 0, ht->callbacks);
365 }
366
367 CF_INLINE uintptr_t __CFBasicHashImportValue2(CFBasicHashRef ht, uintptr_t stack_value) {
368 return ht->callbacks->func(ht, kCFBasicHashCallbackOpRetainValue2, stack_value, 0, ht->callbacks);
369 }
370
371 CF_INLINE uintptr_t __CFBasicHashImportKey(CFBasicHashRef ht, uintptr_t stack_key) {
372 return ht->callbacks->func(ht, kCFBasicHashCallbackOpRetainKey, stack_key, 0, ht->callbacks);
373 }
374
375 CF_INLINE uintptr_t __CFBasicHashImportKey2(CFBasicHashRef ht, uintptr_t stack_key) {
376 return ht->callbacks->func(ht, kCFBasicHashCallbackOpRetainKey2, stack_key, 0, ht->callbacks);
377 }
378
379 CF_INLINE void __CFBasicHashEjectValue(CFBasicHashRef ht, uintptr_t stack_value) {
380 ht->callbacks->func(ht, kCFBasicHashCallbackOpReleaseValue, stack_value, 0, ht->callbacks);
381 }
382
383 CF_INLINE void __CFBasicHashEjectValue2(CFBasicHashRef ht, uintptr_t stack_value) {
384 ht->callbacks->func(ht, kCFBasicHashCallbackOpReleaseValue2, stack_value, 0, ht->callbacks);
385 }
386
387 CF_INLINE void __CFBasicHashEjectKey(CFBasicHashRef ht, uintptr_t stack_key) {
388 ht->callbacks->func(ht, kCFBasicHashCallbackOpReleaseKey, stack_key, 0, ht->callbacks);
389 }
390
391 CF_INLINE void __CFBasicHashEjectKey2(CFBasicHashRef ht, uintptr_t stack_key) {
392 ht->callbacks->func(ht, kCFBasicHashCallbackOpReleaseKey2, stack_key, 0, ht->callbacks);
393 }
394
395 CF_INLINE Boolean __CFBasicHashTestEqualValue(CFBasicHashRef ht, uintptr_t stack_value_a, uintptr_t stack_value_b) {
396 return (Boolean)ht->callbacks->func(ht, kCFBasicHashCallbackOpValueEqual, stack_value_a, stack_value_b, ht->callbacks);
397 }
398
399 CF_INLINE Boolean __CFBasicHashTestEqualValue2(CFBasicHashRef ht, uintptr_t stack_value_a, uintptr_t stack_value_b) {
400 return (Boolean)ht->callbacks->func(ht, kCFBasicHashCallbackOpValue2Equal, stack_value_a, stack_value_b, ht->callbacks);
401 }
402
403 CF_INLINE Boolean __CFBasicHashTestEqualKey(CFBasicHashRef ht, uintptr_t stack_key_a, uintptr_t stack_key_b) {
404 COCOA_HASHTABLE_TEST_EQUAL(ht, stack_key_a, stack_key_b);
405 return (Boolean)ht->callbacks->func(ht, kCFBasicHashCallbackOpKeyEqual, stack_key_a, stack_key_b, ht->callbacks);
406 }
407
408 CF_INLINE Boolean __CFBasicHashTestEqualKey2(CFBasicHashRef ht, uintptr_t stack_key_a, uintptr_t stack_key_b) {
409 COCOA_HASHTABLE_TEST_EQUAL(ht, stack_key_a, stack_key_b);
410 return (Boolean)ht->callbacks->func(ht, kCFBasicHashCallbackOpKey2Equal, stack_key_a, stack_key_b, ht->callbacks);
411 }
412
413 CF_INLINE CFHashCode __CFBasicHashHashKey(CFBasicHashRef ht, uintptr_t stack_key) {
414 CFHashCode hash_code = (CFHashCode)ht->callbacks->func(ht, kCFBasicHashCallbackOpHashKey, stack_key, 0, ht->callbacks);
415 COCOA_HASHTABLE_HASH_KEY(ht, stack_key, hash_code);
416 return hash_code;
417 }
418
419 CF_INLINE CFHashCode __CFBasicHashHashKey2(CFBasicHashRef ht, uintptr_t stack_key) {
420 CFHashCode hash_code = (CFHashCode)ht->callbacks->func(ht, kCFBasicHashCallbackOpHashKey2, stack_key, 0, ht->callbacks);
421 COCOA_HASHTABLE_HASH_KEY(ht, stack_key, hash_code);
422 return hash_code;
423 }
424
425 CF_INLINE void *__CFBasicHashAllocateMemory(CFBasicHashRef ht, CFIndex count, CFIndex elem_size, Boolean strong) {
426 CFAllocatorRef allocator = CFGetAllocator(ht);
427 void *new_mem = NULL;
428 if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) {
429 new_mem = auto_zone_allocate_object(auto_zone(), count * elem_size, strong ? AUTO_MEMORY_SCANNED : AUTO_UNSCANNED, false, false);
430 } else {
431 new_mem = CFAllocatorAllocate(allocator, count * elem_size, 0);
432 }
433 if (!new_mem) HALT;
434 return new_mem;
435 }
436
437
438 // Prime numbers. Values above 100 have been adjusted up so that the
439 // malloced block size will be just below a multiple of 512; values
440 // above 1200 have been adjusted up to just below a multiple of 4096.
441 static const uintptr_t __CFBasicHashTableSizes[64] = {
442 0, 3, 7, 13, 23, 41, 71, 127, 191, 251, 383, 631, 1087, 1723,
443 2803, 4523, 7351, 11959, 19447, 31231, 50683, 81919, 132607,
444 214519, 346607, 561109, 907759, 1468927, 2376191, 3845119,
445 6221311, 10066421, 16287743, 26354171, 42641881, 68996069,
446 111638519, 180634607, 292272623, 472907251,
447 #if __LP64__
448 765180413UL, 1238087663UL, 2003267557UL, 3241355263UL, 5244622819UL,
449 8485977589UL, 13730600407UL, 22216578047UL, 35947178479UL,
450 58163756537UL, 94110934997UL, 152274691561UL, 246385626107UL,
451 398660317687UL, 645045943807UL, 1043706260983UL, 1688752204787UL,
452 2732458465769UL, 4421210670577UL, 7153669136377UL,
453 11574879807461UL, 18728548943849UL, 30303428750843UL
454 #endif
455 };
456
457 // Primitive roots for the primes above
458 static const uintptr_t __CFBasicHashPrimitiveRoots[64] = {
459 0, 2, 3, 2, 5, 6, 7, 3, 19, 6, 5, 3, 3, 3,
460 2, 5, 6, 3, 3, 6, 2, 3, 3,
461 3, 5, 10, 3, 3, 22, 3,
462 3, 3, 5, 2, 22, 2,
463 11, 5, 5, 2,
464 #if __LP64__
465 3, 10, 2, 3, 10,
466 2, 3, 5, 3,
467 3, 2, 7, 2,
468 3, 3, 3, 2,
469 3, 5, 5,
470 2, 3, 2
471 #endif
472 };
473
474 /* Primitive roots under 100 for the primes above
475 3: 2
476 7: 3 5
477 13: 2 6 7 11
478 23: 5 7 10 11 14 15 17 19 20 21
479 41: 6 7 11 12 13 15 17 19 22 24 26 28 29 30 34 35
480 71: 7 11 13 21 22 28 31 33 35 42 44 47 52 53 55 56 59 61 62 63 65 67 68 69
481 127: 3 6 7 12 14 23 29 39 43 45 46 48 53 55 56 57 58 65 67 78 83 85 86 91 92 93 96 97
482 191: 19 21 22 28 29 33 35 42 44 47 53 56 57 58 61 62 63 71 73 74 76 83 87 88 89 91 93 94 95 99
483 251: 6 11 14 18 19 24 26 29 30 33 34 37 42 43 44 46 53 54 55 56 57 59 61 62 70 71 72 76 77 78 82 87 90 95 96 97 98 99
484 383: 5 10 11 13 15 20 22 26 30 33 35 37 39 40 41 44 45 47 52 53 59 60 61 66 70 74 77 78 79 80 82 83 85 88 89 90 91 94 95 97 99
485 631: 3 7 12 13 14 15 19 26 51 53 54 56 59 60 61 63 65 70 75 76 87 93 95 96 99
486 1087: 3 10 12 13 14 20 22 24 28 29 31 38 44 45 46 51 52 53 54 58 59 61 62 63 67 74 75 76 80 89 90 92 94 96 97 99
487 1723: 3 12 17 18 29 30 38 45 46 48 55 63 74 75 77 78 82 83 86 88 94 95
488 2803: 2 11 12 18 20 21 29 30 32 34 35 38 41 46 48 50 52 56 66 67 74 78 79 80 83 84 86 91 93 94 98 99
489 4523: 5 6 7 15 18 20 22 24 26 31 34 41 45 54 55 57 60 65 66 70 72 74 76 77 83 85 88 93 94 96 98
490 7351: 6 7 12 15 17 22 28 31 35 38 44 52 54 55 56 60 65 69 71 75 96
491 11959: 3 6 12 24 29 33 37 39 41 47 48 51 53 57 58 59 66 67 69 73 74 75 78 82 94 96
492 19447: 3 5 6 7 10 12 14 20 23 24 28 29 37 39 45 46 47 51 55 56 58 65 71 73 74 75 78 79 80 82 83 90 91 92 94 96
493 31231: 6 7 24 29 30 33 41 43 48 52 53 54 56 57 59 60 62 65 69 70 73 75 77 83 86
494 50683: 2 3 12 14 17 18 20 32 33 35 39 41 45 50 55 56 57 58 61 62 65 68 69 71 72 74 75 80 84 86 88 93 95
495 81919: 3 12 23 24 26 30 33 43 52 53 54 57 59 60 65 66 75 84 86 87 91 92 93 96 97
496 132607: 3 5 6 17 19 20 21 23 24 26 29 33 34 35 38 40 42 45 48 52 54 61 62 67 71 73 75 79 82 86 89 90 92
497 214519: 3 7 12 15 19 24 26 28 30 33 35 38 41 52 54 56 61 65 69 70 73 77 86 87 89 93 96 97
498 346607: 5 10 14 15 17 19 20 21 28 30 34 38 40 41 42 45 51 55 56 57 59 60 63 65 67 68 76 77 80 82 84 89 90 91 97
499 561109: 10 11 18 21 26 30 33 35 38 40 41 43 46 47 50 51 53 61 62 72 73 74 84 85 91 96
500 907759: 3 6 12 13 17 24 26 33 34 41 47 48 52 57 61 66 68 71 75 79 82 87 89 93 94
501 1468927: 3 5 6 11 20 21 22 23 24 26 35 40 42 45 48 51 52 54 58 71 73 75 77 79 86 88 90 92 93 94 95
502 2376191: 22 29 31 33 37 43 44 47 55 58 59 62 66 77 86 87 88 93 99
503 3845119: 3 11 12 13 15 23 24 30 37 42 43 44 51 52 53 54 55 57 65 73 84 86 87 88 89 92 94 96 97
504 6221311: 3 12 13 15 21 24 30 31 33 46 54 57 61 66 67 74 82 84 87 89 91 92 96
505 10066421: 3 10 11 12 17 18 19 21 23 27 39 40 41 48 50 56 58 60 61 66 68 71 72 73 74 75 76 77 83 85 86 87 92 94 95 97
506 16287743: 5 10 15 20 30 31 35 40 43 45 47 53 55 59 60 61 62 65 70 73 79 80 85 86 89 90 93 94 95
507 26354171: 2 6 7 8 10 17 18 21 22 23 24 26 30 35 38 40 50 51 53 59 62 63 66 67 68 69 71 72 74 77 78 83 84 85 87 88 90 91 96 98
508 42641881: 22 31 38 44 46 57 59 62 67 69 73 76 77 83 92 99
509 68996069: 2 3 8 10 11 12 14 15 17 18 21 26 27 32 37 38 40 43 44 46 47 48 50 53 55 56 58 60 61 62 66 67 68 69 70 72 75 77 82 84 85 87 89 90 93 98 99
510 111638519: 11 13 17 22 26 29 33 34 39 41 44 51 52 53 55 58 59 61 65 66 67 68 71 77 78 79 82 83 85 87 88 91 97 99
511 180634607: 5 10 15 19 20 23 30 31 35 37 38 40 43 45 46 47 55 57 60 62 65 69 70 74 76 79 80 85 86 89 90 92 93 94
512 292272623: 5 10 11 13 15 20 22 23 26 30 31 33 35 39 40 44 45 46 47 52 59 60 61 62 66 67 69 70 71 77 78 79 80 83 85 88 90 91 92 93 94 95 97 99
513 472907251: 2 10 12 14 17 18 29 31 37 46 50 60 61 65 68 70 78 82 84 85 90 91 94 98
514 765180413: 3 5 11 12 14 18 20 21 23 26 27 29 30 34 35 38 39 44 45 47 48 50 51 56 57 59 62 66 67 71 72 73 74 75 77 80 82 84 85 86 89 92 93 95 97 98 99
515 1238087663: 10 13 14 15 20 21 23 28 38 40 41 42 43 45 46 52 55 56 57 60 63 67 69 71 76 78 80 82 84 85 86 89 90 92
516 2003267557: 2 13 14 18 20 22 23 24 31 32 34 37 38 41 43 47 50 54 59 60 67 69 79 80 85 87 91 93 96
517 3241355263: 3 6 10 11 20 21 22 24 34 42 43 45 46 48 54 57 61 65 68 70 71 75 77 78 80 83 86 87 88 92 93 94
518 5244622819: 10 15 17 23 29 31 35 38 40 50 57 60 65 67 68 71 73 74 75 79 90 92 94
519 8485977589: 2 6 10 17 18 19 22 28 30 31 32 35 37 40 47 51 52 54 57 58 59 61 65 66 76 77 79 84 85 86 88 90 93 96 98
520 13730600407: 3 5 10 12 19 24 33 35 40 42 43 45 46 51 54 55 65 73 75 76 78 80 82 84 87 89 92 93 94 96
521 22216578047: 5 10 11 15 17 20 22 30 33 34 35 40 44 45 51 59 60 61 65 66 68 70 73 77 79 80 88 90 95 99
522 35947178479: 3 12 14 15 22 24 29 30 38 41 44 51 54 55 56 58 63 69 70 73 76 78 89 91 95 96 97 99
523 58163756537: 3 5 6 7 10 11 12 14 17 20 22 23 24 27 28 31 39 40 43 44 45 46 47 48 53 54 56 57 59 61 62 63 65 68 71 73 75 78 79 80 86 87 88 89 90 91 92 94 95 96 97 99
524 94110934997: 2 3 5 8 11 12 14 18 19 20 21 23 26 27 29 30 32 34 35 39 41 43 44 48 51 56 59 62 66 67 71 72 74 75 76 77 79 80 84 85 92 93 94 98 99
525 152274691561: 7 17 26 35 37 39 41 42 43 53 56 62 63 65 67 74 82 84 85 89 93 94
526 246385626107UL: 2 5 6 8 11 14 15 18 20 23 24 26 29 31 32 33 34 35 37 38 42 43 44 45 50 54 56 60 61 65 67 69 71 72 77 78 80 82 83 85 87 89 92 93 94 95 96 98 99
527 398660317687UL: 3 5 6 7 11 13 20 24 26 28 40 44 45 48 54 56 59 63 69 75 79 85 88 89 90 93 95 99
528 645045943807UL: 3 5 10 12 21 22 23 24 26 35 37 40 41 44 45 47 51 52 53 59 70 75 79 85 87 92 93 95 96 97 99
529 1043706260983UL: 3 7 11 24 28 29 (<= 32)
530 1688752204787UL: 2 5 6 7 8 13 18 20 21 22 23 24 28 32 (<= 32)
531 2732458465769UL: 3 6 11 12 13 15 17 19 21 22 23 24 26 27 30 31 (<= 32)
532 4421210670577UL: 5 (<= 9)
533
534 */
535
536 static const uintptr_t __CFBasicHashTableCapacities[64] = {
537 0, 3, 6, 11, 19, 32, 52, 85, 118, 155, 237, 390, 672, 1065,
538 1732, 2795, 4543, 7391, 12019, 19302, 31324, 50629, 81956,
539 132580, 214215, 346784, 561026, 907847, 1468567, 2376414,
540 3844982, 6221390, 10066379, 16287773, 26354132, 42641916,
541 68996399, 111638327, 180634415, 292272755,
542 #if __LP64__
543 472907503UL, 765180257UL, 1238087439UL, 2003267722UL, 3241355160UL,
544 5244622578UL, 8485977737UL, 13730600347UL, 22216578100UL,
545 35947178453UL, 58163756541UL, 94110935011UL, 152274691274UL,
546 246385626296UL, 398660317578UL, 645045943559UL, 1043706261135UL,
547 1688752204693UL, 2732458465840UL, 4421210670552UL,
548 7153669136706UL, 11574879807265UL, 18728548943682UL
549 #endif
550 };
551
552 // to expose the load factor, expose this function to customization
553 CF_INLINE CFIndex __CFBasicHashGetCapacityForNumBuckets(CFBasicHashRef ht, CFIndex num_buckets_idx) {
554 return __CFBasicHashTableCapacities[num_buckets_idx];
555 #if 0
556 CFIndex num_buckets = __CFBasicHashTableSizes[num_buckets_idx];
557 if (num_buckets_idx < 8) {
558 double dep = 0.0545665730357293074; // (1 - (sqrt(5) - 1) / 2) / 7
559 double factor = 1.0 - (num_buckets_idx - 1) * dep;
560 return (CFIndex)floor(num_buckets * factor + 0.375); // 0.375 is intentional
561 }
562 double factor = 0.6180339887498948482; // (sqrt(5) - 1) / 2
563 return (CFIndex)floor(num_buckets * factor + 0.5);
564 #endif
565 }
566
567 CF_INLINE CFIndex __CFBasicHashGetNumBucketsIndexForCapacity(CFBasicHashRef ht, CFIndex capacity) {
568 for (CFIndex idx = 0; idx < 64; idx++) {
569 if (capacity <= __CFBasicHashGetCapacityForNumBuckets(ht, idx)) return idx;
570 }
571 HALT;
572 return 0;
573 }
574
575 __private_extern__ CFIndex CFBasicHashGetNumBuckets(CFBasicHashRef ht) {
576 return __CFBasicHashTableSizes[ht->bits.num_buckets_idx];
577 }
578
579 __private_extern__ CFIndex CFBasicHashGetCapacity(CFBasicHashRef ht) {
580 return __CFBasicHashGetCapacityForNumBuckets(ht, ht->bits.num_buckets_idx);
581 }
582
583 // In returned struct, .count is zero if the bucket is empty or deleted,
584 // and the .weak_key field indicates which. .idx is either the index of
585 // the found bucket or the index of the bucket which should be filled by
586 // an add operation. For a set or multiset, the .weak_key and .weak_value
587 // are the same.
588 __private_extern__ CFBasicHashBucket CFBasicHashGetBucket(CFBasicHashRef ht, CFIndex idx) {
589 uintptr_t empty = ((uintptr_t)ht->bits.marker << __CFBasicHashMarkerShift), deleted = ~empty;
590 CFBasicHashBucket result;
591 result.idx = idx;
592 result.weak_value = __CFBasicHashGetValues(ht)[idx].weak;
593 result.weak_value2 = (0 != ht->bits.values2_offset) ? __CFBasicHashGetValues2(ht)[idx].weak : 0;
594 result.weak_key = (0 != ht->bits.keys_offset) ? __CFBasicHashGetKeys(ht)[idx].weak : result.weak_value;
595 result.weak_key2 = (0 != ht->bits.keys2_offset) ? __CFBasicHashGetKeys2(ht)[idx].weak : 0;
596 result.count = (0 != ht->bits.counts_offset) ? __CFBasicHashGetCounts(ht)[idx] : ((result.weak_key == empty || result.weak_key == deleted) ? 0 : 1);
597 result.order = (0 != ht->bits.orders_offset) ? __CFBasicHashGetOrders(ht)[idx] : 0;
598 return result;
599 }
600
601 // During rehashing of a mutable CFBasicHash, we know that there are no
602 // deleted slots and the keys have already been uniqued. When rehashing,
603 // if key_hash is non-0, we use it as the hash code.
604 static CFBasicHashBucket ___CFBasicHashFindBucket1(CFBasicHashRef ht, uintptr_t stack_key, uintptr_t key_hash, Boolean rehashing) {
605 CFHashCode hash_code = key_hash ? key_hash : __CFBasicHashHashKey(ht, stack_key);
606 uintptr_t empty = ((uintptr_t)ht->bits.marker << __CFBasicHashMarkerShift), deleted = ~empty;
607 CFBasicHashValue *keys = (0 != ht->bits.keys_offset) ? __CFBasicHashGetKeys(ht) : __CFBasicHashGetValues(ht);
608 uintptr_t *hashes = (0 != ht->bits.hashes_offset) ? __CFBasicHashGetHashes(ht) : NULL;
609 uintptr_t num_buckets = __CFBasicHashTableSizes[ht->bits.num_buckets_idx];
610 CFBasicHashBucket result = {kCFNotFound, deleted, 0, deleted, 0, 0, 0};
611
612 uintptr_t h1 = 0;
613 // Linear probing, with c = 1
614 // probe[0] = h1(k)
615 // probe[i] = (h1(k) + i * c) mod num_buckets, i = 1 .. num_buckets - 1
616 // h1(k) = k mod num_buckets
617 h1 = hash_code % num_buckets;
618
619 COCOA_HASHTABLE_PROBING_START(ht, num_buckets);
620 uintptr_t probe = h1;
621 for (CFIndex idx = 0; idx < num_buckets; idx++) {
622 uintptr_t stack_curr = keys[probe].weak;
623 if (stack_curr == empty) {
624 COCOA_HASHTABLE_PROBE_EMPTY(ht, probe);
625 if (kCFNotFound == result.idx) {
626 result.idx = probe;
627 result.weak_value = empty;
628 result.weak_key = empty;
629 }
630 COCOA_HASHTABLE_PROBING_END(ht, idx + 1);
631 return result;
632 } else if (__builtin_expect(!rehashing, 0)) {
633 if (stack_curr == deleted) {
634 COCOA_HASHTABLE_PROBE_DELETED(ht, probe);
635 if (kCFNotFound == result.idx) {
636 result.idx = probe;
637 }
638 } else {
639 COCOA_HASHTABLE_PROBE_VALID(ht, probe);
640 if (stack_curr == stack_key || ((!hashes || hashes[probe] == hash_code) && __CFBasicHashTestEqualKey(ht, stack_curr, stack_key))) {
641 COCOA_HASHTABLE_PROBING_END(ht, idx + 1);
642 result.idx = probe;
643 result.weak_value = (0 != ht->bits.keys_offset) ? __CFBasicHashGetValues(ht)[probe].weak : stack_curr;
644 result.weak_value2 = (0 != ht->bits.values2_offset) ? __CFBasicHashGetValues2(ht)[probe].weak : 0;
645 result.weak_key = stack_curr;
646 result.weak_key2 = (0 != ht->bits.keys2_offset) ? __CFBasicHashGetKeys2(ht)[probe].weak : 0;
647 result.count = (0 != ht->bits.counts_offset) ? __CFBasicHashGetCounts(ht)[probe] : 1;
648 result.order = (0 != ht->bits.orders_offset) ? __CFBasicHashGetOrders(ht)[probe] : 1;
649 return result;
650 }
651 }
652 }
653 // Linear probing, with c = 1
654 probe += 1;
655 if (__builtin_expect(num_buckets <= probe, 0)) {
656 probe -= num_buckets;
657 }
658 }
659 COCOA_HASHTABLE_PROBING_END(ht, num_buckets);
660 return result; // all buckets full or deleted, return first deleted element which was found
661 }
662
663 static CFBasicHashBucket ___CFBasicHashFindBucket2(CFBasicHashRef ht, uintptr_t stack_key, uintptr_t key_hash, Boolean rehashing) {
664 CFHashCode hash_code = key_hash ? key_hash : __CFBasicHashHashKey(ht, stack_key);
665 uintptr_t empty = ((uintptr_t)ht->bits.marker << __CFBasicHashMarkerShift), deleted = ~empty;
666 CFBasicHashValue *keys = (0 != ht->bits.keys_offset) ? __CFBasicHashGetKeys(ht) : __CFBasicHashGetValues(ht);
667 uintptr_t *hashes = (0 != ht->bits.hashes_offset) ? __CFBasicHashGetHashes(ht) : NULL;
668 uintptr_t num_buckets = __CFBasicHashTableSizes[ht->bits.num_buckets_idx];
669 CFBasicHashBucket result = {kCFNotFound, deleted, 0, deleted, 0, 0, 0};
670
671 uintptr_t h1 = 0, h2 = 0;
672 // Double hashing
673 // probe[0] = h1(k)
674 // probe[i] = (h1(k) + i * h2(k)) mod num_buckets, i = 1 .. num_buckets - 1
675 // h1(k) = k mod num_buckets
676 // h2(k) = floor(k / num_buckets) mod num_buckets
677 h1 = hash_code % num_buckets;
678 h2 = (hash_code / num_buckets) % num_buckets;
679 if (0 == h2) h2 = num_buckets - 1;
680
681 COCOA_HASHTABLE_PROBING_START(ht, num_buckets);
682 uintptr_t probe = h1;
683 for (CFIndex idx = 0; idx < num_buckets; idx++) {
684 uintptr_t stack_curr = keys[probe].weak;
685 if (stack_curr == empty) {
686 COCOA_HASHTABLE_PROBE_EMPTY(ht, probe);
687 if (kCFNotFound == result.idx) {
688 result.idx = probe;
689 result.weak_value = empty;
690 result.weak_key = empty;
691 }
692 COCOA_HASHTABLE_PROBING_END(ht, idx + 1);
693 return result;
694 } else if (__builtin_expect(!rehashing, 0)) {
695 if (stack_curr == deleted) {
696 COCOA_HASHTABLE_PROBE_DELETED(ht, probe);
697 if (kCFNotFound == result.idx) {
698 result.idx = probe;
699 }
700 } else {
701 COCOA_HASHTABLE_PROBE_VALID(ht, probe);
702 if (stack_curr == stack_key || ((!hashes || hashes[probe] == hash_code) && __CFBasicHashTestEqualKey(ht, stack_curr, stack_key))) {
703 COCOA_HASHTABLE_PROBING_END(ht, idx + 1);
704 result.idx = probe;
705 result.weak_value = (0 != ht->bits.keys_offset) ? __CFBasicHashGetValues(ht)[probe].weak : stack_curr;
706 result.weak_value2 = (0 != ht->bits.values2_offset) ? __CFBasicHashGetValues2(ht)[probe].weak : 0;
707 result.weak_key = stack_curr;
708 result.weak_key2 = (0 != ht->bits.keys2_offset) ? __CFBasicHashGetKeys2(ht)[probe].weak : 0;
709 result.count = (0 != ht->bits.counts_offset) ? __CFBasicHashGetCounts(ht)[probe] : 1;
710 result.order = (0 != ht->bits.orders_offset) ? __CFBasicHashGetOrders(ht)[probe] : 1;
711 return result;
712 }
713 }
714 }
715 // Double hashing
716 probe += h2;
717 if (__builtin_expect(num_buckets <= probe, 1)) {
718 probe -= num_buckets;
719 }
720 }
721 COCOA_HASHTABLE_PROBING_END(ht, num_buckets);
722 return result; // all buckets full or deleted, return first deleted element which was found
723 }
724
725 static CFBasicHashBucket ___CFBasicHashFindBucket3(CFBasicHashRef ht, uintptr_t stack_key, uintptr_t key_hash, Boolean rehashing) {
726 CFHashCode hash_code = key_hash ? key_hash : __CFBasicHashHashKey(ht, stack_key);
727 uintptr_t empty = ((uintptr_t)ht->bits.marker << __CFBasicHashMarkerShift), deleted = ~empty;
728 CFBasicHashValue *keys = (0 != ht->bits.keys_offset) ? __CFBasicHashGetKeys(ht) : __CFBasicHashGetValues(ht);
729 uintptr_t *hashes = (0 != ht->bits.hashes_offset) ? __CFBasicHashGetHashes(ht) : NULL;
730 uintptr_t num_buckets = __CFBasicHashTableSizes[ht->bits.num_buckets_idx];
731 CFBasicHashBucket result = {kCFNotFound, deleted, 0, deleted, 0, 0, 0};
732
733 uintptr_t h1 = 0, h2 = 0, pr = 0;
734 // Improved exponential hashing
735 // probe[0] = h1(k)
736 // probe[i] = (h1(k) + pr(k)^i * h2(k)) mod num_buckets, i = 1 .. num_buckets - 1
737 // h1(k) = k mod num_buckets
738 // h2(k) = floor(k / num_buckets) mod num_buckets
739 // note: h2(k) has the effect of rotating the sequence if it is constant
740 // note: pr(k) is any primitive root of num_buckets, varying this gives different sequences
741 h1 = hash_code % num_buckets;
742 h2 = (hash_code / num_buckets) % num_buckets;
743 if (0 == h2) h2 = num_buckets - 1;
744 pr = __CFBasicHashPrimitiveRoots[ht->bits.num_buckets_idx];
745
746 COCOA_HASHTABLE_PROBING_START(ht, num_buckets);
747 uintptr_t probe = h1, acc = pr;
748 for (CFIndex idx = 0; idx < num_buckets; idx++) {
749 uintptr_t stack_curr = keys[probe].weak;
750 if (stack_curr == empty) {
751 COCOA_HASHTABLE_PROBE_EMPTY(ht, probe);
752 if (kCFNotFound == result.idx) {
753 result.idx = probe;
754 result.weak_value = empty;
755 result.weak_key = empty;
756 }
757 COCOA_HASHTABLE_PROBING_END(ht, idx + 1);
758 return result;
759 } else if (__builtin_expect(!rehashing, 0)) {
760 if (stack_curr == deleted) {
761 COCOA_HASHTABLE_PROBE_DELETED(ht, probe);
762 if (kCFNotFound == result.idx) {
763 result.idx = probe;
764 }
765 } else {
766 COCOA_HASHTABLE_PROBE_VALID(ht, probe);
767 if (stack_curr == stack_key || ((!hashes || hashes[probe] == hash_code) && __CFBasicHashTestEqualKey(ht, stack_curr, stack_key))) {
768 COCOA_HASHTABLE_PROBING_END(ht, idx + 1);
769 result.idx = probe;
770 result.weak_value = (0 != ht->bits.keys_offset) ? __CFBasicHashGetValues(ht)[probe].weak : stack_curr;
771 result.weak_value2 = (0 != ht->bits.values2_offset) ? __CFBasicHashGetValues2(ht)[probe].weak : 0;
772 result.weak_key = stack_curr;
773 result.weak_key2 = (0 != ht->bits.keys2_offset) ? __CFBasicHashGetKeys2(ht)[probe].weak : 0;
774 result.count = (0 != ht->bits.counts_offset) ? __CFBasicHashGetCounts(ht)[probe] : 1;
775 result.order = (0 != ht->bits.orders_offset) ? __CFBasicHashGetOrders(ht)[probe] : 1;
776 return result;
777 }
778 }
779 }
780 // Improved exponential hashing
781 probe = h1 + h2 * acc;
782 if (__builtin_expect(num_buckets <= probe, 1)) {
783 probe = probe % num_buckets;
784 }
785 acc = acc * pr;
786 if (__builtin_expect(num_buckets <= acc, 1)) {
787 acc = acc % num_buckets;
788 }
789 }
790 COCOA_HASHTABLE_PROBING_END(ht, num_buckets);
791 return result; // all buckets full or deleted, return first deleted element which was found
792 }
793
794 CF_INLINE CFBasicHashBucket ___CFBasicHashFindBucket(CFBasicHashRef ht, uintptr_t stack_key, uintptr_t key_hash, Boolean rehashing) {
795 switch (ht->bits.hash_style) {
796 case __kCFBasicHashLinearHashingValue:
797 return ___CFBasicHashFindBucket1(ht, stack_key, 0, rehashing);
798 case __kCFBasicHashDoubleHashingValue:
799 return ___CFBasicHashFindBucket2(ht, stack_key, 0, rehashing);
800 case __kCFBasicHashExponentialHashingValue:
801 return ___CFBasicHashFindBucket3(ht, stack_key, 0, rehashing);
802 }
803 HALT;
804 CFBasicHashBucket result = {kCFNotFound, 0, 0, 0};
805 return result;
806 }
807
808 CF_INLINE CFBasicHashBucket __CFBasicHashFindBucket(CFBasicHashRef ht, uintptr_t stack_key) {
809 if (0 == ht->bits.num_buckets_idx) {
810 uintptr_t empty = ((uintptr_t)ht->bits.marker << __CFBasicHashMarkerShift);
811 CFBasicHashBucket result = {kCFNotFound, empty, empty, 0};
812 return result;
813 }
814 return ___CFBasicHashFindBucket(ht, stack_key, 0, false);
815 }
816
817 __private_extern__ CFBasicHashBucket CFBasicHashFindBucket(CFBasicHashRef ht, uintptr_t stack_key) {
818 return __CFBasicHashFindBucket(ht, stack_key);
819 }
820
821 __private_extern__ CFOptionFlags CFBasicHashGetFlags(CFBasicHashRef ht) {
822 CFOptionFlags flags = (ht->bits.hash_style << 13);
823 if (ht->bits.strong_values) flags |= kCFBasicHashStrongValues;
824 if (ht->bits.strong_values2) flags |= kCFBasicHashStrongValues2;
825 if (ht->bits.strong_keys) flags |= kCFBasicHashStrongKeys;
826 if (ht->bits.strong_keys2) flags |= kCFBasicHashStrongKeys2;
827 if (ht->bits.fast_grow) flags |= kCFBasicHashAggressiveGrowth;
828 if (ht->bits.values2_offset) flags |= kCFBasicHashHasValues2;
829 if (ht->bits.keys_offset) flags |= kCFBasicHashHasKeys;
830 if (ht->bits.keys2_offset) flags |= kCFBasicHashHasKeys2;
831 if (ht->bits.counts_offset) flags |= kCFBasicHashHasCounts;
832 if (ht->bits.orders_offset) flags |= kCFBasicHashHasOrder;
833 if (ht->bits.hashes_offset) flags |= kCFBasicHashHasHashCache;
834 return flags;
835 }
836
837 __private_extern__ CFIndex CFBasicHashGetCount(CFBasicHashRef ht) {
838 if (0 != ht->bits.counts_offset) {
839 CFIndex total = 0L;
840 CFIndex cnt = (CFIndex)__CFBasicHashTableSizes[ht->bits.num_buckets_idx];
841 uintptr_t *counts = __CFBasicHashGetCounts(ht);
842 for (CFIndex idx = 0; idx < cnt; idx++) {
843 total += counts[idx];
844 }
845 return total;
846 }
847 return (CFIndex)ht->bits.used_buckets;
848 }
849
850 __private_extern__ CFIndex CFBasicHashGetCountOfKey(CFBasicHashRef ht, uintptr_t stack_key) {
851 if (0L == ht->bits.used_buckets) {
852 return 0L;
853 }
854 return __CFBasicHashFindBucket(ht, stack_key).count;
855 }
856
857 __private_extern__ CFIndex CFBasicHashGetCountOfValue(CFBasicHashRef ht, uintptr_t stack_value) {
858 if (0L == ht->bits.used_buckets) {
859 return 0L;
860 }
861 if (!(0 != ht->bits.keys_offset)) {
862 return __CFBasicHashFindBucket(ht, stack_value).count;
863 }
864 __block CFIndex total = 0L;
865 CFBasicHashApply(ht, ^(CFBasicHashBucket bkt) {
866 if ((stack_value == bkt.weak_value) || __CFBasicHashTestEqualValue(ht, bkt.weak_value, stack_value)) total += bkt.count;
867 return (Boolean)true;
868 });
869 return total;
870 }
871
872 __private_extern__ Boolean CFBasicHashesAreEqual(CFBasicHashRef ht1, CFBasicHashRef ht2) {
873 CFIndex cnt1 = CFBasicHashGetCount(ht1);
874 if (cnt1 != CFBasicHashGetCount(ht2)) return false;
875 if (0 == cnt1) return true;
876 __block Boolean equal = true;
877 CFBasicHashApply(ht1, ^(CFBasicHashBucket bkt1) {
878 CFBasicHashBucket bkt2 = __CFBasicHashFindBucket(ht2, bkt1.weak_key);
879 if (bkt1.count != bkt2.count) {
880 equal = false;
881 return (Boolean)false;
882 }
883 if ((0 != ht1->bits.keys_offset) && (bkt1.weak_value != bkt2.weak_value) && !__CFBasicHashTestEqualValue(ht1, bkt1.weak_value, bkt2.weak_value)) {
884 equal = false;
885 return (Boolean)false;
886 }
887 return (Boolean)true;
888 });
889 return equal;
890 }
891
892 __private_extern__ void CFBasicHashApply(CFBasicHashRef ht, Boolean (^block)(CFBasicHashBucket)) {
893 CFIndex used = (CFIndex)ht->bits.used_buckets, cnt = (CFIndex)__CFBasicHashTableSizes[ht->bits.num_buckets_idx];
894 for (CFIndex idx = 0; 0 < used && idx < cnt; idx++) {
895 CFBasicHashBucket bkt = CFBasicHashGetBucket(ht, idx);
896 if (0 < bkt.count) {
897 if (!block(bkt)) {
898 return;
899 }
900 used--;
901 }
902 }
903 }
904
905 __private_extern__ void CFBasicHashGetElements(CFBasicHashRef ht, CFIndex bufferslen, uintptr_t *weak_values, uintptr_t *weak_values2, uintptr_t *weak_keys, uintptr_t *weak_keys2) {
906 CFIndex used = (CFIndex)ht->bits.used_buckets, cnt = (CFIndex)__CFBasicHashTableSizes[ht->bits.num_buckets_idx];
907 uintptr_t empty = ((uintptr_t)ht->bits.marker << __CFBasicHashMarkerShift), deleted = ~empty;
908 CFBasicHashValue *values = __CFBasicHashGetValues(ht);
909 CFBasicHashValue *values2 = (0 != ht->bits.values2_offset) ? __CFBasicHashGetValues2(ht) : NULL;
910 CFBasicHashValue *keys = (0 != ht->bits.keys_offset) ? __CFBasicHashGetKeys(ht) : NULL;
911 CFBasicHashValue *keys2 = (0 != ht->bits.keys2_offset) ? __CFBasicHashGetKeys2(ht) : NULL;
912 uintptr_t *counts = (0 != ht->bits.counts_offset) ? __CFBasicHashGetCounts(ht) : NULL;
913 CFIndex offset = 0;
914 for (CFIndex idx = 0; 0 < used && idx < cnt && offset < bufferslen; idx++) {
915 uintptr_t weak_key = keys ? keys[idx].weak : values[idx].weak;
916 uintptr_t count = counts ? counts[idx] : ((weak_key == empty || weak_key == deleted) ? 0 : 1);
917 if (0 < count) {
918 used--;
919 for (CFIndex cnt = count; cnt-- && offset < bufferslen;) {
920 if (weak_values) { weak_values[offset] = values[idx].weak; }
921 if (weak_values2) { weak_values2[offset] = values2 ? values2[idx].weak : 0; }
922 if (weak_keys) { weak_keys[offset] = weak_key; }
923 if (weak_keys2) { weak_keys2[offset] = keys2 ? keys2[idx].weak : 0; }
924 offset++;
925 }
926 }
927 }
928 }
929
930 __private_extern__ unsigned long __CFBasicHashFastEnumeration(CFBasicHashRef ht, struct __objcFastEnumerationStateEquivalent2 *state, void *stackbuffer, unsigned long count) {
931 /* copy as many as count items over */
932 if (0 == state->state) { /* first time */
933 state->mutationsPtr = (unsigned long *)&ht->bits + (__LP64__ ? 1 : 3);
934 }
935 state->itemsPtr = (unsigned long *)stackbuffer;
936 CFIndex cntx = 0;
937 CFIndex used = (CFIndex)ht->bits.used_buckets, cnt = (CFIndex)__CFBasicHashTableSizes[ht->bits.num_buckets_idx];
938 for (CFIndex idx = (CFIndex)state->state; 0 < used && idx < cnt && cntx < (CFIndex)count; idx++) {
939 CFBasicHashBucket bkt = CFBasicHashGetBucket(ht, idx);
940 if (0 < bkt.count) {
941 state->itemsPtr[cntx++] = (unsigned long)bkt.weak_key;
942 used--;
943 }
944 state->state++;
945 }
946 return cntx;
947 }
948
949 #if ENABLE_MEMORY_COUNTERS
950 static volatile int64_t __CFBasicHashTotalCount = 0ULL;
951 static volatile int64_t __CFBasicHashTotalSize = 0ULL;
952 static volatile int64_t __CFBasicHashPeakCount = 0ULL;
953 static volatile int64_t __CFBasicHashPeakSize = 0ULL;
954 static volatile int32_t __CFBasicHashSizes[64] = {0};
955 #endif
956
957 static void __CFBasicHashDrain(CFBasicHashRef ht, Boolean forFinalization) {
958 #if ENABLE_MEMORY_COUNTERS
959 OSAtomicAdd64Barrier(-1 * (int64_t) CFBasicHashGetSize(ht, true), & __CFBasicHashTotalSize);
960 #endif
961
962 uintptr_t empty = ((uintptr_t)ht->bits.marker << __CFBasicHashMarkerShift), deleted = ~empty;
963 CFIndex old_num_buckets = __CFBasicHashTableSizes[ht->bits.num_buckets_idx];
964
965 CFAllocatorRef allocator = CFGetAllocator(ht);
966 Boolean nullify = (!forFinalization || !CF_IS_COLLECTABLE_ALLOCATOR(allocator));
967
968 CFBasicHashValue *old_values = NULL, *old_values2 = NULL, *old_keys = NULL, *old_keys2 = NULL;
969 uintptr_t *old_counts = NULL, *old_orders = NULL, *old_hashes = NULL;
970
971 old_values = __CFBasicHashGetValues(ht);
972 if (nullify) __CFBasicHashSetValues(ht, NULL);
973 if (0 != ht->bits.values2_offset) {
974 old_values2 = __CFBasicHashGetValues2(ht);
975 if (nullify) __CFBasicHashSetValues2(ht, NULL);
976 }
977 if (0 != ht->bits.keys_offset) {
978 old_keys = __CFBasicHashGetKeys(ht);
979 if (nullify) __CFBasicHashSetKeys(ht, NULL);
980 }
981 if (0 != ht->bits.keys2_offset) {
982 old_keys2 = __CFBasicHashGetKeys2(ht);
983 if (nullify) __CFBasicHashSetKeys2(ht, NULL);
984 }
985 if (0 != ht->bits.counts_offset) {
986 old_counts = __CFBasicHashGetCounts(ht);
987 if (nullify) __CFBasicHashSetCounts(ht, NULL);
988 }
989 if (0 != ht->bits.orders_offset) {
990 old_orders = __CFBasicHashGetOrders(ht);
991 if (nullify) __CFBasicHashSetOrders(ht, NULL);
992 }
993 if (0 != ht->bits.hashes_offset) {
994 old_hashes = __CFBasicHashGetHashes(ht);
995 if (nullify) __CFBasicHashSetHashes(ht, NULL);
996 }
997
998 if (nullify) {
999 ht->bits.mutations++;
1000 ht->bits.num_buckets_idx = 0;
1001 ht->bits.used_buckets = 0;
1002 ht->bits.marker = 0;
1003 ht->bits.deleted = 0;
1004 }
1005
1006 if (ht->callbacks != &CFBasicHashNullCallbacks) {
1007 CFBasicHashValue *keys = old_keys ? old_keys : old_values;
1008 for (CFIndex idx = 0; idx < old_num_buckets; idx++) {
1009 uintptr_t stack_key = keys[idx].weak;
1010 if (stack_key != empty && stack_key != deleted) {
1011 __CFBasicHashEjectValue(ht, old_values[idx].weak);
1012 if (old_values2) {
1013 __CFBasicHashEjectValue2(ht, old_values2[idx].weak);
1014 }
1015 if (old_keys) {
1016 __CFBasicHashEjectKey(ht, old_keys[idx].weak);
1017 }
1018 if (old_keys2) {
1019 __CFBasicHashEjectKey2(ht, old_keys2[idx].weak);
1020 }
1021 }
1022 }
1023 }
1024
1025 if (forFinalization) {
1026 ht->callbacks->func(ht, kCFBasicHashCallbackOpFreeCallbacks, (uintptr_t)allocator, 0, ht->callbacks);
1027 }
1028
1029 if (!CF_IS_COLLECTABLE_ALLOCATOR(allocator)) {
1030 CFAllocatorDeallocate(allocator, old_values);
1031 CFAllocatorDeallocate(allocator, old_values2);
1032 CFAllocatorDeallocate(allocator, old_keys);
1033 CFAllocatorDeallocate(allocator, old_keys2);
1034 CFAllocatorDeallocate(allocator, old_counts);
1035 CFAllocatorDeallocate(allocator, old_orders);
1036 CFAllocatorDeallocate(allocator, old_hashes);
1037 }
1038
1039 #if ENABLE_MEMORY_COUNTERS
1040 int64_t size_now = OSAtomicAdd64Barrier((int64_t) CFBasicHashGetSize(ht, true), & __CFBasicHashTotalSize);
1041 while (__CFBasicHashPeakSize < size_now && !OSAtomicCompareAndSwap64Barrier(__CFBasicHashPeakSize, size_now, & __CFBasicHashPeakSize));
1042 #endif
1043 }
1044
1045 static void __CFBasicHashRehash(CFBasicHashRef ht, CFIndex newItemCount) {
1046 #if ENABLE_MEMORY_COUNTERS
1047 OSAtomicAdd64Barrier(-1 * (int64_t) CFBasicHashGetSize(ht, true), & __CFBasicHashTotalSize);
1048 OSAtomicAdd32Barrier(-1, &__CFBasicHashSizes[ht->bits.num_buckets_idx]);
1049 #endif
1050
1051 if (COCOA_HASHTABLE_REHASH_START_ENABLED()) COCOA_HASHTABLE_REHASH_START(ht, CFBasicHashGetNumBuckets(ht), CFBasicHashGetSize(ht, true));
1052
1053 CFIndex new_num_buckets_idx = ht->bits.num_buckets_idx;
1054 if (0 != newItemCount) {
1055 if (newItemCount < 0) newItemCount = 0;
1056 CFIndex new_capacity_req = ht->bits.used_buckets + newItemCount;
1057 new_num_buckets_idx = __CFBasicHashGetNumBucketsIndexForCapacity(ht, new_capacity_req);
1058 if (1 == newItemCount && ht->bits.fast_grow) {
1059 new_num_buckets_idx++;
1060 }
1061 }
1062
1063 CFIndex new_num_buckets = __CFBasicHashTableSizes[new_num_buckets_idx];
1064 CFIndex old_num_buckets = __CFBasicHashTableSizes[ht->bits.num_buckets_idx];
1065
1066 CFBasicHashValue *new_values = NULL, *new_values2 = NULL, *new_keys = NULL, *new_keys2 = NULL;
1067 uintptr_t *new_counts = NULL, *new_orders = NULL, *new_hashes = NULL;
1068
1069 if (0 < new_num_buckets) {
1070 new_values = (CFBasicHashValue *)__CFBasicHashAllocateMemory(ht, new_num_buckets, sizeof(CFBasicHashValue), ht->bits.strong_values);
1071 __SetLastAllocationEventName(new_values, "CFBasicHash (value-store)");
1072 if (0 != ht->bits.values2_offset) {
1073 new_values2 = (CFBasicHashValue *)__CFBasicHashAllocateMemory(ht, new_num_buckets, sizeof(CFBasicHashValue), ht->bits.strong_values2);
1074 __SetLastAllocationEventName(new_values2, "CFBasicHash (value2-store)");
1075 }
1076 if (0 != ht->bits.keys_offset) {
1077 new_keys = (CFBasicHashValue *)__CFBasicHashAllocateMemory(ht, new_num_buckets, sizeof(CFBasicHashValue), ht->bits.strong_keys);
1078 __SetLastAllocationEventName(new_keys, "CFBasicHash (key-store)");
1079 }
1080 if (0 != ht->bits.keys2_offset) {
1081 new_keys2 = (CFBasicHashValue *)__CFBasicHashAllocateMemory(ht, new_num_buckets, sizeof(CFBasicHashValue), ht->bits.strong_keys2);
1082 __SetLastAllocationEventName(new_keys2, "CFBasicHash (key2-store)");
1083 }
1084 if (0 != ht->bits.counts_offset) {
1085 new_counts = (uintptr_t *)__CFBasicHashAllocateMemory(ht, new_num_buckets, sizeof(uintptr_t), false);
1086 __SetLastAllocationEventName(new_counts, "CFBasicHash (count-store)");
1087 memset(new_counts, 0, new_num_buckets * sizeof(uintptr_t));
1088 }
1089 if (0 != ht->bits.orders_offset) {
1090 new_orders = (uintptr_t *)__CFBasicHashAllocateMemory(ht, new_num_buckets, sizeof(uintptr_t), false);
1091 __SetLastAllocationEventName(new_orders, "CFBasicHash (order-store)");
1092 memset(new_orders, 0, new_num_buckets * sizeof(uintptr_t));
1093 }
1094 if (0 != ht->bits.hashes_offset) {
1095 new_hashes = (uintptr_t *)__CFBasicHashAllocateMemory(ht, new_num_buckets, sizeof(uintptr_t), false);
1096 __SetLastAllocationEventName(new_hashes, "CFBasicHash (hash-store)");
1097 memset(new_hashes, 0, new_num_buckets * sizeof(uintptr_t));
1098 }
1099 }
1100
1101 uintptr_t empty = ((uintptr_t)ht->bits.marker << __CFBasicHashMarkerShift), deleted = ~empty;
1102 // if we knew the allocations were coming from already-cleared memory, and the marker was still 0, we could skip all this next stuff
1103 for (CFIndex idx = 0; idx < new_num_buckets; idx++) {
1104 if (ht->bits.strong_values) new_values[idx].strong = (id)empty; else new_values[idx].weak = empty;
1105 if (new_values2) {
1106 if (ht->bits.strong_values2) new_values2[idx].strong = (id)empty; else new_values2[idx].weak = empty;
1107 }
1108 if (new_keys) {
1109 if (ht->bits.strong_keys) new_keys[idx].strong = (id)empty; else new_keys[idx].weak = empty;
1110 }
1111 if (new_keys2) {
1112 if (ht->bits.strong_keys2) new_keys2[idx].strong = (id)empty; else new_keys2[idx].weak = empty;
1113 }
1114 }
1115
1116 ht->bits.num_buckets_idx = new_num_buckets_idx;
1117 ht->bits.deleted = 0;
1118
1119 CFBasicHashValue *old_values = NULL, *old_values2 = NULL, *old_keys = NULL, *old_keys2 = NULL;
1120 uintptr_t *old_counts = NULL, *old_orders = NULL, *old_hashes = NULL;
1121
1122 old_values = __CFBasicHashGetValues(ht);
1123 __CFBasicHashSetValues(ht, new_values);
1124 if (0 != ht->bits.values2_offset) {
1125 old_values2 = __CFBasicHashGetValues2(ht);
1126 __CFBasicHashSetValues2(ht, new_values2);
1127 }
1128 if (0 != ht->bits.keys_offset) {
1129 old_keys = __CFBasicHashGetKeys(ht);
1130 __CFBasicHashSetKeys(ht, new_keys);
1131 }
1132 if (0 != ht->bits.keys2_offset) {
1133 old_keys2 = __CFBasicHashGetKeys2(ht);
1134 __CFBasicHashSetKeys2(ht, new_keys2);
1135 }
1136 if (0 != ht->bits.counts_offset) {
1137 old_counts = __CFBasicHashGetCounts(ht);
1138 __CFBasicHashSetCounts(ht, new_counts);
1139 }
1140 if (0 != ht->bits.orders_offset) {
1141 old_orders = __CFBasicHashGetOrders(ht);
1142 __CFBasicHashSetOrders(ht, new_orders);
1143 }
1144 if (0 != ht->bits.hashes_offset) {
1145 old_hashes = __CFBasicHashGetHashes(ht);
1146 __CFBasicHashSetHashes(ht, new_hashes);
1147 }
1148
1149 if (0 < old_num_buckets) {
1150 CFBasicHashValue *keys = old_keys ? old_keys : old_values;
1151 for (CFIndex idx = 0; idx < old_num_buckets; idx++) {
1152 uintptr_t stack_key = keys[idx].weak;
1153 if (stack_key != empty && stack_key != deleted) {
1154 CFBasicHashBucket bkt = ___CFBasicHashFindBucket(ht, stack_key, old_hashes ? old_hashes[idx] : 0, true);
1155 uintptr_t stack_value = old_values[idx].weak;
1156 if (ht->bits.strong_values) new_values[bkt.idx].strong = (id)stack_value; else new_values[bkt.idx].weak = stack_value;
1157 if (old_values2) {
1158 if (ht->bits.strong_values2) new_values2[bkt.idx].strong = (id)old_values2[idx].weak; else new_values2[bkt.idx].weak = old_values2[idx].weak;
1159 }
1160 if (old_keys) {
1161 if (ht->bits.strong_keys) new_keys[bkt.idx].strong = (id)stack_key; else new_keys[bkt.idx].weak = stack_key;
1162 }
1163 if (old_keys2) {
1164 if (ht->bits.strong_keys2) new_keys2[bkt.idx].strong = (id)old_keys2[idx].weak; else new_keys2[bkt.idx].weak = old_keys2[idx].weak;
1165 }
1166 if (old_counts) {
1167 new_counts[bkt.idx] = old_counts[idx];
1168 }
1169 if (old_orders) {
1170 new_orders[bkt.idx] = old_orders[idx];
1171 }
1172 if (old_hashes) {
1173 new_hashes[bkt.idx] = old_hashes[idx];
1174 }
1175 }
1176 }
1177 }
1178
1179 CFAllocatorRef allocator = CFGetAllocator(ht);
1180 if (!CF_IS_COLLECTABLE_ALLOCATOR(allocator)) {
1181 CFAllocatorDeallocate(allocator, old_values);
1182 CFAllocatorDeallocate(allocator, old_values2);
1183 CFAllocatorDeallocate(allocator, old_keys);
1184 CFAllocatorDeallocate(allocator, old_keys2);
1185 CFAllocatorDeallocate(allocator, old_counts);
1186 CFAllocatorDeallocate(allocator, old_orders);
1187 CFAllocatorDeallocate(allocator, old_hashes);
1188 }
1189
1190 if (COCOA_HASHTABLE_REHASH_END_ENABLED()) COCOA_HASHTABLE_REHASH_END(ht, CFBasicHashGetNumBuckets(ht), CFBasicHashGetSize(ht, true));
1191
1192 #if ENABLE_MEMORY_COUNTERS
1193 int64_t size_now = OSAtomicAdd64Barrier((int64_t) CFBasicHashGetSize(ht, true), &__CFBasicHashTotalSize);
1194 while (__CFBasicHashPeakSize < size_now && !OSAtomicCompareAndSwap64Barrier(__CFBasicHashPeakSize, size_now, & __CFBasicHashPeakSize));
1195 OSAtomicAdd32Barrier(1, &__CFBasicHashSizes[ht->bits.num_buckets_idx]);
1196 #endif
1197 }
1198
1199 __private_extern__ void CFBasicHashSetCapacity(CFBasicHashRef ht, CFIndex capacity) {
1200 if (!CFBasicHashIsMutable(ht)) HALT;
1201 if (ht->bits.used_buckets < capacity) {
1202 ht->bits.mutations++;
1203 __CFBasicHashRehash(ht, capacity - ht->bits.used_buckets);
1204 }
1205 }
1206
1207 static void __CFBasicHashFindNewMarker(CFBasicHashRef ht, uintptr_t stack_key) {
1208 uintptr_t marker = ht->bits.marker;
1209 uintptr_t empty = (marker << __CFBasicHashMarkerShift), deleted = ~empty;
1210 CFBasicHashValue *keys = (0 != ht->bits.keys_offset) ? __CFBasicHashGetKeys(ht) : __CFBasicHashGetValues(ht);
1211 Boolean strong = (0 != ht->bits.keys_offset) ? ht->bits.strong_keys : ht->bits.strong_values;
1212 CFIndex cnt = __CFBasicHashTableSizes[ht->bits.num_buckets_idx];
1213 if (0 == marker) marker = 4096;
1214
1215 again:;
1216 marker++;
1217 if ((1UL << 26) <= marker) HALT;
1218 uintptr_t new_empty = (marker << __CFBasicHashMarkerShift), new_deleted = ~new_empty;
1219 if (stack_key == new_empty || stack_key == new_deleted) {
1220 goto again;
1221 }
1222 for (CFIndex idx = 0; idx < cnt; idx++) {
1223 uintptr_t stack_curr = strong ? (uintptr_t)keys[idx].strong : keys[idx].weak;
1224 if (stack_curr == new_empty || stack_curr == new_deleted) {
1225 goto again;
1226 }
1227 }
1228 for (CFIndex idx = 0; idx < cnt; idx++) {
1229 uintptr_t stack_curr = strong ? (uintptr_t)keys[idx].strong : keys[idx].weak;
1230 if (stack_curr == empty) {
1231 if (strong) keys[idx].strong = (id)new_empty; else keys[idx].weak = new_empty;
1232 } else if (stack_curr == deleted) {
1233 if (strong) keys[idx].strong = (id)new_deleted; else keys[idx].weak = new_deleted;
1234 }
1235 }
1236 ht->bits.marker = marker;
1237 }
1238
1239 static void __CFBasicHashAddValue(CFBasicHashRef ht, CFBasicHashBucket bkt, uintptr_t stack_key, uintptr_t stack_key2, uintptr_t stack_value, uintptr_t stack_value2) {
1240 ht->bits.mutations++;
1241 stack_value = __CFBasicHashImportValue(ht, stack_value);
1242 if (0 != ht->bits.keys_offset) {
1243 stack_key = __CFBasicHashImportKey(ht, stack_key);
1244 } else {
1245 stack_key = stack_value;
1246 }
1247 if (0 != ht->bits.values2_offset) {
1248 stack_value2 = __CFBasicHashImportValue2(ht, stack_value2);
1249 }
1250 if (0 != ht->bits.keys2_offset) {
1251 stack_key2 = __CFBasicHashImportKey2(ht, stack_key2);
1252 }
1253 if (CFBasicHashGetCapacity(ht) < ht->bits.used_buckets + 1) {
1254 __CFBasicHashRehash(ht, 1);
1255 bkt = ___CFBasicHashFindBucket(ht, stack_key, 0, true);
1256 }
1257 uintptr_t empty = ((uintptr_t)ht->bits.marker << __CFBasicHashMarkerShift), deleted = ~empty;
1258 if (bkt.weak_key == deleted) {
1259 ht->bits.deleted--;
1260 }
1261 if (stack_key == empty || stack_key == deleted) {
1262 __CFBasicHashFindNewMarker(ht, stack_key);
1263 }
1264 CFBasicHashValue *value = &(__CFBasicHashGetValues(ht)[bkt.idx]);
1265 if (ht->bits.strong_values) value->strong = (id)stack_value; else value->weak = stack_value;
1266 if (0 != ht->bits.values2_offset) {
1267 CFBasicHashValue *value2 = &(__CFBasicHashGetValues2(ht)[bkt.idx]);
1268 if (ht->bits.strong_values2) value2->strong = (id)stack_value2; else value2->weak = stack_value2;
1269 }
1270 if (0 != ht->bits.keys_offset) {
1271 CFBasicHashValue *key = &(__CFBasicHashGetKeys(ht)[bkt.idx]);
1272 if (ht->bits.strong_keys) key->strong = (id)stack_key; else key->weak = stack_key;
1273 }
1274 if (0 != ht->bits.keys2_offset) {
1275 CFBasicHashValue *key2 = &(__CFBasicHashGetKeys2(ht)[bkt.idx]);
1276 if (ht->bits.strong_keys2) key2->strong = (id)stack_key2; else key2->weak = stack_key2;
1277 }
1278 if (0 != ht->bits.counts_offset) {
1279 __CFBasicHashGetCounts(ht)[bkt.idx] = 1;
1280 }
1281 if (0 != ht->bits.orders_offset) {
1282 __CFBasicHashGetOrders(ht)[bkt.idx] = 0;
1283 }
1284 if (ht->bits.hashes_offset) {
1285 __CFBasicHashGetHashes(ht)[bkt.idx] = __CFBasicHashHashKey(ht, stack_key);
1286 }
1287 ht->bits.used_buckets++;
1288 }
1289
1290 static void __CFBasicHashReplaceValue(CFBasicHashRef ht, CFBasicHashBucket bkt, uintptr_t stack_key, uintptr_t stack_key2, uintptr_t stack_value, uintptr_t stack_value2) {
1291 ht->bits.mutations++;
1292 stack_value = __CFBasicHashImportValue(ht, stack_value);
1293 if (0 != ht->bits.keys_offset) {
1294 stack_key = __CFBasicHashImportKey(ht, stack_key);
1295 } else {
1296 stack_key = stack_value;
1297 }
1298 if (0 != ht->bits.values2_offset) {
1299 stack_value2 = __CFBasicHashImportValue2(ht, stack_value2);
1300 }
1301 if (0 != ht->bits.keys2_offset) {
1302 stack_key2 = __CFBasicHashImportKey2(ht, stack_key2);
1303 }
1304 uintptr_t empty = ((uintptr_t)ht->bits.marker << __CFBasicHashMarkerShift), deleted = ~empty;
1305 if (stack_key == empty || stack_key == deleted) {
1306 __CFBasicHashFindNewMarker(ht, stack_key);
1307 }
1308 CFBasicHashValue *value = &(__CFBasicHashGetValues(ht)[bkt.idx]);
1309 uintptr_t old_value = value->weak;
1310 if (ht->bits.strong_values) value->strong = (id)stack_value; else value->weak = stack_value;
1311 __CFBasicHashEjectValue(ht, old_value);
1312 if (0 != ht->bits.values2_offset) {
1313 CFBasicHashValue *value2 = &(__CFBasicHashGetValues2(ht)[bkt.idx]);
1314 uintptr_t old_value2 = value2->weak;
1315 if (ht->bits.strong_values2) value2->strong = (id)stack_value2; else value2->weak = stack_value2;
1316 __CFBasicHashEjectValue2(ht, old_value2);
1317 }
1318 if (0 != ht->bits.keys_offset) {
1319 CFBasicHashValue *key = &(__CFBasicHashGetKeys(ht)[bkt.idx]);
1320 uintptr_t old_key = key->weak;
1321 if (ht->bits.strong_keys) key->strong = (id)stack_key; else key->weak = stack_key;
1322 __CFBasicHashEjectKey(ht, old_key);
1323 }
1324 if (0 != ht->bits.keys2_offset) {
1325 CFBasicHashValue *key2 = &(__CFBasicHashGetKeys2(ht)[bkt.idx]);
1326 uintptr_t old_key2 = key2->weak;
1327 if (ht->bits.strong_keys2) key2->strong = (id)stack_key2; else key2->weak = stack_key2;
1328 __CFBasicHashEjectKey2(ht, old_key2);
1329 }
1330 }
1331
1332 static void __CFBasicHashRemoveValue(CFBasicHashRef ht, CFBasicHashBucket bkt, uintptr_t stack_key, uintptr_t stack_key2) {
1333 ht->bits.mutations++;
1334 uintptr_t empty = ((uintptr_t)ht->bits.marker << __CFBasicHashMarkerShift), deleted = ~empty;
1335 CFBasicHashValue *value = &(__CFBasicHashGetValues(ht)[bkt.idx]);
1336 uintptr_t old_value = value->weak;
1337 if (ht->bits.strong_values) value->strong = (id)deleted; else value->weak = deleted;
1338 __CFBasicHashEjectValue(ht, old_value);
1339 if (0 != ht->bits.values2_offset) {
1340 CFBasicHashValue *value2 = &(__CFBasicHashGetValues2(ht)[bkt.idx]);
1341 uintptr_t old_value2 = value2->weak;
1342 if (ht->bits.strong_values2) value2->strong = (id)deleted; else value2->weak = deleted;
1343 __CFBasicHashEjectValue2(ht, old_value2);
1344 }
1345 if (0 != ht->bits.keys_offset) {
1346 CFBasicHashValue *key = &(__CFBasicHashGetKeys(ht)[bkt.idx]);
1347 uintptr_t old_key = key->weak;
1348 if (ht->bits.strong_keys) key->strong = (id)deleted; else key->weak = deleted;
1349 __CFBasicHashEjectKey(ht, old_key);
1350 }
1351 if (0 != ht->bits.keys2_offset) {
1352 CFBasicHashValue *key2 = &(__CFBasicHashGetKeys2(ht)[bkt.idx]);
1353 uintptr_t old_key2 = key2->weak;
1354 if (ht->bits.strong_keys2) key2->strong = (id)deleted; else key2->weak = deleted;
1355 __CFBasicHashEjectKey2(ht, old_key2);
1356 }
1357 if (0 != ht->bits.counts_offset) {
1358 __CFBasicHashGetCounts(ht)[bkt.idx] = 0;
1359 }
1360 if (0 != ht->bits.orders_offset) {
1361 __CFBasicHashGetOrders(ht)[bkt.idx] = 0;
1362 }
1363 if (ht->bits.hashes_offset) {
1364 __CFBasicHashGetHashes(ht)[bkt.idx] = 0;
1365 }
1366 ht->bits.used_buckets--;
1367 ht->bits.deleted++;
1368 Boolean do_shrink = false;
1369 if (ht->bits.fast_grow) { // == slow shrink
1370 do_shrink = (5 < ht->bits.num_buckets_idx && ht->bits.used_buckets < __CFBasicHashGetCapacityForNumBuckets(ht, ht->bits.num_buckets_idx - 5));
1371 } else {
1372 do_shrink = (2 < ht->bits.num_buckets_idx && ht->bits.used_buckets < __CFBasicHashGetCapacityForNumBuckets(ht, ht->bits.num_buckets_idx - 2));
1373 }
1374 if (do_shrink) {
1375 __CFBasicHashRehash(ht, -1);
1376 return;
1377 }
1378 do_shrink = (0 == ht->bits.deleted); // .deleted roll-over
1379 CFIndex num_buckets = __CFBasicHashTableSizes[ht->bits.num_buckets_idx];
1380 do_shrink = do_shrink || ((20 <= num_buckets) && (num_buckets / 4 <= ht->bits.deleted));
1381 if (do_shrink) {
1382 __CFBasicHashRehash(ht, 0);
1383 }
1384 }
1385
1386 __private_extern__ void CFBasicHashAddValue(CFBasicHashRef ht, uintptr_t stack_key, uintptr_t stack_value) {
1387 if (!CFBasicHashIsMutable(ht)) HALT;
1388 CFBasicHashBucket bkt = __CFBasicHashFindBucket(ht, stack_key);
1389 if (0 < bkt.count) {
1390 ht->bits.mutations++;
1391 if (0 != ht->bits.counts_offset) {
1392 __CFBasicHashGetCounts(ht)[bkt.idx]++;
1393 }
1394 } else {
1395 __CFBasicHashAddValue(ht, bkt, stack_key, 0, stack_value, 0);
1396 }
1397 }
1398
1399 __private_extern__ void CFBasicHashReplaceValue(CFBasicHashRef ht, uintptr_t stack_key, uintptr_t stack_value) {
1400 if (!CFBasicHashIsMutable(ht)) HALT;
1401 CFBasicHashBucket bkt = __CFBasicHashFindBucket(ht, stack_key);
1402 if (0 < bkt.count) {
1403 __CFBasicHashReplaceValue(ht, bkt, stack_key, 0, stack_value, 0);
1404 }
1405 }
1406
1407 __private_extern__ void CFBasicHashSetValue(CFBasicHashRef ht, uintptr_t stack_key, uintptr_t stack_value) {
1408 if (!CFBasicHashIsMutable(ht)) HALT;
1409 CFBasicHashBucket bkt = __CFBasicHashFindBucket(ht, stack_key);
1410 if (0 < bkt.count) {
1411 __CFBasicHashReplaceValue(ht, bkt, stack_key, 0, stack_value, 0);
1412 } else {
1413 __CFBasicHashAddValue(ht, bkt, stack_key, 0, stack_value, 0);
1414 }
1415 }
1416
1417 __private_extern__ CFIndex CFBasicHashRemoveValue(CFBasicHashRef ht, uintptr_t stack_key) {
1418 if (!CFBasicHashIsMutable(ht)) HALT;
1419 CFBasicHashBucket bkt = __CFBasicHashFindBucket(ht, stack_key);
1420 if (1 < bkt.count) {
1421 ht->bits.mutations++;
1422 if (0 != ht->bits.counts_offset) {
1423 __CFBasicHashGetCounts(ht)[bkt.idx]--;
1424 }
1425 } else if (0 < bkt.count) {
1426 __CFBasicHashRemoveValue(ht, bkt, stack_key, 0);
1427 }
1428 return bkt.count;
1429 }
1430
1431 __private_extern__ void CFBasicHashRemoveAllValues(CFBasicHashRef ht) {
1432 if (!CFBasicHashIsMutable(ht)) HALT;
1433 if (0 == ht->bits.num_buckets_idx) return;
1434 __CFBasicHashDrain(ht, false);
1435 }
1436
1437 __private_extern__ size_t CFBasicHashGetSize(CFBasicHashRef ht, Boolean total) {
1438 size_t size = sizeof(struct __CFBasicHash);
1439 if (0 != ht->bits.values2_offset) size += sizeof(CFBasicHashValue *);
1440 if (0 != ht->bits.keys_offset) size += sizeof(CFBasicHashValue *);
1441 if (0 != ht->bits.keys2_offset) size += sizeof(CFBasicHashValue *);
1442 if (0 != ht->bits.counts_offset) size += sizeof(uintptr_t *);
1443 if (0 != ht->bits.orders_offset) size += sizeof(uintptr_t *);
1444 if (0 != ht->bits.hashes_offset) size += sizeof(uintptr_t *);
1445 if (total) {
1446 CFIndex num_buckets = __CFBasicHashTableSizes[ht->bits.num_buckets_idx];
1447 if (0 < num_buckets) {
1448 size += malloc_size(__CFBasicHashGetValues(ht));
1449 if (0 != ht->bits.values2_offset) size += malloc_size(__CFBasicHashGetValues2(ht));
1450 if (0 != ht->bits.keys_offset) size += malloc_size(__CFBasicHashGetKeys(ht));
1451 if (0 != ht->bits.keys2_offset) size += malloc_size(__CFBasicHashGetKeys2(ht));
1452 if (0 != ht->bits.counts_offset) size += malloc_size(__CFBasicHashGetCounts(ht));
1453 if (0 != ht->bits.orders_offset) size += malloc_size(__CFBasicHashGetOrders(ht));
1454 if (0 != ht->bits.hashes_offset) size += malloc_size(__CFBasicHashGetHashes(ht));
1455 size += malloc_size((void *)ht->callbacks);
1456 }
1457 }
1458 return size;
1459 }
1460
1461 __private_extern__ CFStringRef CFBasicHashCopyDescription(CFBasicHashRef ht, Boolean detailed, CFStringRef prefix, CFStringRef entryPrefix, Boolean describeElements) {
1462 CFMutableStringRef result = CFStringCreateMutable(kCFAllocatorSystemDefault, 0);
1463 CFStringAppendFormat(result, NULL, CFSTR("%@{type = %s %s%s, count = %ld,\n"), prefix, (CFBasicHashIsMutable(ht) ? "mutable" : "immutable"), ((0 != ht->bits.counts_offset) ? "multi" : ""), ((0 != ht->bits.keys_offset) ? "dict" : "set"), CFBasicHashGetCount(ht));
1464 if (detailed) {
1465 const char *cb_type = "custom";
1466 if (&CFBasicHashNullCallbacks == ht->callbacks) {
1467 cb_type = "null";
1468 } else if (&CFBasicHashStandardCallbacks == ht->callbacks) {
1469 cb_type = "standard";
1470 }
1471 CFStringAppendFormat(result, NULL, CFSTR("%@hash cache = %s, strong values = %s, strong keys = %s, cb = %s,\n"), prefix, ((0 != ht->bits.hashes_offset) ? "yes" : "no"), (ht->bits.strong_values ? "yes" : "no"), (ht->bits.strong_keys ? "yes" : "no"), cb_type);
1472 CFStringAppendFormat(result, NULL, CFSTR("%@num bucket index = %d, num buckets = %ld, capacity = %ld, num buckets used = %ld,\n"), prefix, ht->bits.num_buckets_idx, CFBasicHashGetNumBuckets(ht), CFBasicHashGetCapacity(ht), ht->bits.used_buckets);
1473 uintptr_t empty = ((uintptr_t)ht->bits.marker << __CFBasicHashMarkerShift), deleted = ~empty;
1474 CFStringAppendFormat(result, NULL, CFSTR("%@empty marker = 0x%lx, deleted marker = 0x%lx, finalized = %s,\n"), prefix, empty, deleted, (ht->bits.finalized ? "yes" : "no"));
1475 CFStringAppendFormat(result, NULL, CFSTR("%@num mutations = %ld, num deleted = %ld, size = %ld, total size = %ld,\n"), prefix, ht->bits.mutations, ht->bits.deleted, CFBasicHashGetSize(ht, false), CFBasicHashGetSize(ht, true));
1476 CFStringAppendFormat(result, NULL, CFSTR("%@values ptr = %p, keys ptr = %p, counts ptr = %p, hashes ptr = %p,\n"), prefix, __CFBasicHashGetValues(ht), ((0 != ht->bits.keys_offset) ? __CFBasicHashGetKeys(ht) : NULL), ((0 != ht->bits.counts_offset) ? __CFBasicHashGetCounts(ht) : NULL), ((0 != ht->bits.hashes_offset) ? __CFBasicHashGetHashes(ht) : NULL));
1477 }
1478 CFStringAppendFormat(result, NULL, CFSTR("%@entries =>\n"), prefix);
1479 CFBasicHashApply(ht, ^(CFBasicHashBucket bkt) {
1480 CFStringRef vDesc = NULL, kDesc = NULL;
1481 CFBasicHashCallbackType cb = ht->callbacks->func;
1482 if (!describeElements) cb = __CFBasicHashNullCallback;
1483 vDesc = (CFStringRef)cb(ht, kCFBasicHashCallbackOpDescribeValue, bkt.weak_value, 0, ht->callbacks);
1484 if (0 != ht->bits.keys_offset) {
1485 kDesc = (CFStringRef)cb(ht, kCFBasicHashCallbackOpDescribeKey, bkt.weak_key, 0, ht->callbacks);
1486 }
1487 if ((0 != ht->bits.keys_offset) && (0 != ht->bits.counts_offset)) {
1488 CFStringAppendFormat(result, NULL, CFSTR("%@%ld : %@ = %@ (%ld)\n"), entryPrefix, bkt.idx, kDesc, vDesc, bkt.count);
1489 } else if (0 != ht->bits.keys_offset) {
1490 CFStringAppendFormat(result, NULL, CFSTR("%@%ld : %@ = %@\n"), entryPrefix, bkt.idx, kDesc, vDesc);
1491 } else if (0 != ht->bits.counts_offset) {
1492 CFStringAppendFormat(result, NULL, CFSTR("%@%ld : %@ (%ld)\n"), entryPrefix, bkt.idx, vDesc, bkt.count);
1493 } else {
1494 CFStringAppendFormat(result, NULL, CFSTR("%@%ld : %@\n"), entryPrefix, bkt.idx, vDesc);
1495 }
1496 if (kDesc) CFRelease(kDesc);
1497 if (vDesc) CFRelease(vDesc);
1498 return (Boolean)true;
1499 });
1500 CFStringAppendFormat(result, NULL, CFSTR("%@}\n"), prefix);
1501 return result;
1502 }
1503
1504 __private_extern__ void CFBasicHashShow(CFBasicHashRef ht) {
1505 CFStringRef str = CFBasicHashCopyDescription(ht, true, CFSTR(""), CFSTR("\t"), false);
1506 CFShow(str);
1507 CFRelease(str);
1508 }
1509
1510 __private_extern__ Boolean __CFBasicHashEqual(CFTypeRef cf1, CFTypeRef cf2) {
1511 CFBasicHashRef ht1 = (CFBasicHashRef)cf1;
1512 CFBasicHashRef ht2 = (CFBasicHashRef)cf2;
1513 //#warning this used to require that the key and value equal callbacks were pointer identical
1514 return CFBasicHashesAreEqual(ht1, ht2);
1515 }
1516
1517 __private_extern__ CFHashCode __CFBasicHashHash(CFTypeRef cf) {
1518 CFBasicHashRef ht = (CFBasicHashRef)cf;
1519 return CFBasicHashGetCount(ht);
1520 }
1521
1522 __private_extern__ CFStringRef __CFBasicHashCopyDescription(CFTypeRef cf) {
1523 CFBasicHashRef ht = (CFBasicHashRef)cf;
1524 CFStringRef desc = CFBasicHashCopyDescription(ht, false, CFSTR(""), CFSTR("\t"), true);
1525 CFStringRef result = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<CFBasicHash %p [%p]>%@"), cf, CFGetAllocator(cf), desc);
1526 CFRelease(desc);
1527 return result;
1528 }
1529
1530 __private_extern__ void __CFBasicHashDeallocate(CFTypeRef cf) {
1531 CFBasicHashRef ht = (CFBasicHashRef)cf;
1532 if (ht->bits.finalized) HALT;
1533 ht->bits.finalized = 1;
1534 __CFBasicHashDrain(ht, true);
1535 #if ENABLE_MEMORY_COUNTERS
1536 OSAtomicAdd64Barrier(-1, &__CFBasicHashTotalCount);
1537 OSAtomicAdd32Barrier(-1, &__CFBasicHashSizes[ht->bits.num_buckets_idx]);
1538 #endif
1539 }
1540
1541 static CFTypeID __kCFBasicHashTypeID = _kCFRuntimeNotATypeID;
1542
1543 static const CFRuntimeClass __CFBasicHashClass = {
1544 _kCFRuntimeScannedObject,
1545 "CFBasicHash",
1546 NULL, // init
1547 NULL, // copy
1548 __CFBasicHashDeallocate,
1549 __CFBasicHashEqual,
1550 __CFBasicHashHash,
1551 NULL, //
1552 __CFBasicHashCopyDescription
1553 };
1554
1555 __private_extern__ CFTypeID CFBasicHashGetTypeID(void) {
1556 if (_kCFRuntimeNotATypeID == __kCFBasicHashTypeID) __kCFBasicHashTypeID = _CFRuntimeRegisterClass(&__CFBasicHashClass);
1557 return __kCFBasicHashTypeID;
1558 }
1559
1560 CFBasicHashRef CFBasicHashCreate(CFAllocatorRef allocator, CFOptionFlags flags, const CFBasicHashCallbacks *cb) {
1561 size_t size = sizeof(struct __CFBasicHash) - sizeof(CFRuntimeBase);
1562 if (flags & kCFBasicHashHasValues2) size += sizeof(CFBasicHashValue *); // values2
1563 if (flags & kCFBasicHashHasKeys) size += sizeof(CFBasicHashValue *); // keys
1564 if (flags & kCFBasicHashHasKeys2) size += sizeof(CFBasicHashValue *); // keys2
1565 if (flags & kCFBasicHashHasCounts) size += sizeof(uintptr_t *); // counts
1566 if (flags & kCFBasicHashHasOrder) size += sizeof(uintptr_t *); // order
1567 if (flags & kCFBasicHashHasHashCache) size += sizeof(uintptr_t *); // hashes
1568 CFBasicHashRef ht = (CFBasicHashRef)_CFRuntimeCreateInstance(allocator, CFBasicHashGetTypeID(), size, NULL);
1569 if (NULL == ht) HALT;
1570
1571 ht->bits.finalized = 0;
1572 ht->bits.strong_values = (flags & kCFBasicHashStrongValues) ? 1 : 0;
1573 ht->bits.strong_values2 = 0;
1574 ht->bits.strong_keys = (flags & kCFBasicHashStrongKeys) ? 1 : 0;
1575 ht->bits.strong_keys2 = 0;
1576 ht->bits.hash_style = (flags >> 13) & 0x3;
1577 ht->bits.fast_grow = (flags & kCFBasicHashAggressiveGrowth) ? 1 : 0;
1578 ht->bits.__0 = 0;
1579 ht->bits.num_buckets_idx = 0;
1580 ht->bits.used_buckets = 0;
1581 ht->bits.marker = 0;
1582 ht->bits.deleted = 0;
1583 ht->bits.mutations = 1;
1584
1585 uint64_t offset = 1;
1586 ht->bits.values2_offset = 0;
1587 ht->bits.keys_offset = (flags & kCFBasicHashHasKeys) ? offset++ : 0;
1588 ht->bits.keys2_offset = 0;
1589 ht->bits.counts_offset = (flags & kCFBasicHashHasCounts) ? offset++ : 0;
1590 ht->bits.orders_offset = 0;
1591 ht->bits.hashes_offset = (flags & kCFBasicHashHasHashCache) ? offset++ : 0;
1592
1593 __AssignWithWriteBarrier(&ht->callbacks, cb);
1594 for (CFIndex idx = 0; idx < offset; idx++) {
1595 ht->pointers[idx] = NULL;
1596 }
1597
1598 #if ENABLE_MEMORY_COUNTERS
1599 int64_t size_now = OSAtomicAdd64Barrier((int64_t) CFBasicHashGetSize(ht, true), & __CFBasicHashTotalSize);
1600 while (__CFBasicHashPeakSize < size_now && !OSAtomicCompareAndSwap64Barrier(__CFBasicHashPeakSize, size_now, & __CFBasicHashPeakSize));
1601 int64_t count_now = OSAtomicAdd64Barrier(1, & __CFBasicHashTotalCount);
1602 while (__CFBasicHashPeakCount < count_now && !OSAtomicCompareAndSwap64Barrier(__CFBasicHashPeakCount, count_now, & __CFBasicHashPeakCount));
1603 OSAtomicAdd32Barrier(1, &__CFBasicHashSizes[ht->bits.num_buckets_idx]);
1604 #endif
1605
1606 return ht;
1607 }
1608
1609 CFBasicHashRef CFBasicHashCreateCopy(CFAllocatorRef allocator, CFBasicHashRef src_ht) {
1610 size_t size = CFBasicHashGetSize(src_ht, false) - sizeof(CFRuntimeBase);
1611 CFBasicHashRef ht = (CFBasicHashRef)_CFRuntimeCreateInstance(allocator, CFBasicHashGetTypeID(), size, NULL);
1612 if (NULL == ht) HALT;
1613
1614 memmove((uint8_t *)ht + sizeof(CFRuntimeBase), (uint8_t *)src_ht + sizeof(CFRuntimeBase), sizeof(ht->bits));
1615 if (kCFUseCollectableAllocator && !CF_IS_COLLECTABLE_ALLOCATOR(allocator)) {
1616 ht->bits.strong_values = 0;
1617 ht->bits.strong_values2 = 0;
1618 ht->bits.strong_keys = 0;
1619 ht->bits.strong_keys2 = 0;
1620 }
1621 ht->bits.finalized = 0;
1622 ht->bits.mutations = 1;
1623 __AssignWithWriteBarrier(&ht->callbacks, src_ht->callbacks->func(ht, kCFBasicHashCallbackOpCopyCallbacks, (uintptr_t)allocator, 0, src_ht->callbacks));
1624 if (NULL == ht->callbacks) HALT;
1625
1626 CFIndex new_num_buckets = __CFBasicHashTableSizes[ht->bits.num_buckets_idx];
1627 if (0 == new_num_buckets) {
1628 #if ENABLE_MEMORY_COUNTERS
1629 int64_t size_now = OSAtomicAdd64Barrier((int64_t) CFBasicHashGetSize(ht, true), & __CFBasicHashTotalSize);
1630 while (__CFBasicHashPeakSize < size_now && !OSAtomicCompareAndSwap64Barrier(__CFBasicHashPeakSize, size_now, & __CFBasicHashPeakSize));
1631 int64_t count_now = OSAtomicAdd64Barrier(1, & __CFBasicHashTotalCount);
1632 while (__CFBasicHashPeakCount < count_now && !OSAtomicCompareAndSwap64Barrier(__CFBasicHashPeakCount, count_now, & __CFBasicHashPeakCount));
1633 OSAtomicAdd32Barrier(1, &__CFBasicHashSizes[ht->bits.num_buckets_idx]);
1634 #endif
1635 return ht;
1636 }
1637
1638 CFBasicHashValue *new_values = NULL, *new_values2 = NULL, *new_keys = NULL, *new_keys2 = NULL;
1639 uintptr_t *new_counts = NULL, *new_orders = NULL, *new_hashes = NULL;
1640
1641 if (0 < new_num_buckets) {
1642 new_values = (CFBasicHashValue *)__CFBasicHashAllocateMemory(ht, new_num_buckets, sizeof(CFBasicHashValue), ht->bits.strong_values);
1643 __SetLastAllocationEventName(new_values, "CFBasicHash (value-store)");
1644 if (0 != ht->bits.values2_offset) {
1645 new_values2 = (CFBasicHashValue *)__CFBasicHashAllocateMemory(ht, new_num_buckets, sizeof(CFBasicHashValue), ht->bits.strong_values2);
1646 __SetLastAllocationEventName(new_values2, "CFBasicHash (value2-store)");
1647 }
1648 if (0 != ht->bits.keys_offset) {
1649 new_keys = (CFBasicHashValue *)__CFBasicHashAllocateMemory(ht, new_num_buckets, sizeof(CFBasicHashValue), ht->bits.strong_keys);
1650 __SetLastAllocationEventName(new_keys, "CFBasicHash (key-store)");
1651 }
1652 if (0 != ht->bits.keys2_offset) {
1653 new_keys2 = (CFBasicHashValue *)__CFBasicHashAllocateMemory(ht, new_num_buckets, sizeof(CFBasicHashValue), ht->bits.strong_keys2);
1654 __SetLastAllocationEventName(new_keys2, "CFBasicHash (key2-store)");
1655 }
1656 if (0 != ht->bits.counts_offset) {
1657 new_counts = (uintptr_t *)__CFBasicHashAllocateMemory(ht, new_num_buckets, sizeof(uintptr_t), false);
1658 __SetLastAllocationEventName(new_counts, "CFBasicHash (count-store)");
1659 }
1660 if (0 != ht->bits.orders_offset) {
1661 new_orders = (uintptr_t *)__CFBasicHashAllocateMemory(ht, new_num_buckets, sizeof(uintptr_t), false);
1662 __SetLastAllocationEventName(new_orders, "CFBasicHash (order-store)");
1663 }
1664 if (0 != ht->bits.hashes_offset) {
1665 new_hashes = (uintptr_t *)__CFBasicHashAllocateMemory(ht, new_num_buckets, sizeof(uintptr_t), false);
1666 __SetLastAllocationEventName(new_hashes, "CFBasicHash (hash-store)");
1667 }
1668 }
1669
1670 uintptr_t empty = ((uintptr_t)ht->bits.marker << __CFBasicHashMarkerShift), deleted = ~empty;
1671 CFBasicHashValue *old_values = NULL, *old_values2 = NULL, *old_keys = NULL, *old_keys2 = NULL;
1672 uintptr_t *old_counts = NULL, *old_orders = NULL, *old_hashes = NULL;
1673 old_values = __CFBasicHashGetValues(src_ht);
1674 if (0 != src_ht->bits.values2_offset) {
1675 old_values2 = __CFBasicHashGetValues2(src_ht);
1676 }
1677 if (0 != src_ht->bits.keys_offset) {
1678 old_keys = __CFBasicHashGetKeys(src_ht);
1679 }
1680 if (0 != src_ht->bits.keys2_offset) {
1681 old_keys2 = __CFBasicHashGetKeys2(src_ht);
1682 }
1683 if (0 != src_ht->bits.counts_offset) {
1684 old_counts = __CFBasicHashGetCounts(src_ht);
1685 }
1686 if (0 != src_ht->bits.orders_offset) {
1687 old_orders = __CFBasicHashGetOrders(src_ht);
1688 }
1689 if (0 != src_ht->bits.hashes_offset) {
1690 old_hashes = __CFBasicHashGetHashes(src_ht);
1691 }
1692
1693 CFBasicHashValue *keys = old_keys ? old_keys : old_values;
1694 for (CFIndex idx = 0; idx < new_num_buckets; idx++) {
1695 uintptr_t stack_key = keys[idx].weak;
1696 if (stack_key != empty && stack_key != deleted) {
1697 uintptr_t stack_value = __CFBasicHashImportValue(ht, old_values[idx].weak);
1698 if (ht->bits.strong_values) new_values[idx].strong = (id)stack_value; else new_values[idx].weak = stack_value;
1699 if (new_values2) {
1700 uintptr_t stack_value2 = __CFBasicHashImportValue2(ht, old_values2[idx].weak);
1701 if (ht->bits.strong_values2) new_values2[idx].strong = (id)stack_value2; else new_values2[idx].weak = stack_value2;
1702 }
1703 if (new_keys) {
1704 uintptr_t stack_key = __CFBasicHashImportKey(ht, old_keys[idx].weak);
1705 if (ht->bits.strong_keys) new_keys[idx].strong = (id)stack_key; else new_keys[idx].weak = stack_key;
1706 }
1707 if (new_keys2) {
1708 uintptr_t stack_key2 = __CFBasicHashImportKey2(ht, old_keys2[idx].weak);
1709 if (ht->bits.strong_keys2) new_keys2[idx].strong = (id)stack_key2; else new_keys2[idx].weak = stack_key2;
1710 }
1711 } else {
1712 if (ht->bits.strong_values) new_values[idx].strong = (id)stack_key; else new_values[idx].weak = stack_key;
1713 if (new_values2) {
1714 if (ht->bits.strong_values2) new_values2[idx].strong = (id)stack_key; else new_values2[idx].weak = stack_key;
1715 }
1716 if (new_keys) {
1717 if (ht->bits.strong_keys) new_keys[idx].strong = (id)stack_key; else new_keys[idx].weak = stack_key;
1718 }
1719 if (new_keys2) {
1720 if (ht->bits.strong_keys2) new_keys2[idx].strong = (id)stack_key; else new_keys2[idx].weak = stack_key;
1721 }
1722 }
1723 }
1724 if (new_counts) memmove(new_counts, old_counts, new_num_buckets * sizeof(uintptr_t));
1725 if (new_orders) memmove(new_orders, old_orders, new_num_buckets * sizeof(uintptr_t));
1726 if (new_hashes) memmove(new_hashes, old_hashes, new_num_buckets * sizeof(uintptr_t));
1727
1728 __CFBasicHashSetValues(ht, new_values);
1729 if (new_values2) {
1730 __CFBasicHashSetValues2(ht, new_values2);
1731 }
1732 if (new_keys) {
1733 __CFBasicHashSetKeys(ht, new_keys);
1734 }
1735 if (new_keys2) {
1736 __CFBasicHashSetKeys2(ht, new_keys2);
1737 }
1738 if (new_counts) {
1739 __CFBasicHashSetCounts(ht, new_counts);
1740 }
1741 if (new_orders) {
1742 __CFBasicHashSetOrders(ht, new_orders);
1743 }
1744 if (new_hashes) {
1745 __CFBasicHashSetHashes(ht, new_hashes);
1746 }
1747
1748 #if ENABLE_MEMORY_COUNTERS
1749 int64_t size_now = OSAtomicAdd64Barrier((int64_t) CFBasicHashGetSize(ht, true), & __CFBasicHashTotalSize);
1750 while (__CFBasicHashPeakSize < size_now && !OSAtomicCompareAndSwap64Barrier(__CFBasicHashPeakSize, size_now, & __CFBasicHashPeakSize));
1751 int64_t count_now = OSAtomicAdd64Barrier(1, & __CFBasicHashTotalCount);
1752 while (__CFBasicHashPeakCount < count_now && !OSAtomicCompareAndSwap64Barrier(__CFBasicHashPeakCount, count_now, & __CFBasicHashPeakCount));
1753 OSAtomicAdd32Barrier(1, &__CFBasicHashSizes[ht->bits.num_buckets_idx]);
1754 #endif
1755
1756 return ht;
1757 }
1758
1759 void _CFbhx588461(CFBasicHashRef ht, Boolean growth) {
1760 if (!CFBasicHashIsMutable(ht)) HALT;
1761 if (ht->bits.finalized) HALT;
1762 ht->bits.fast_grow = growth ? 1 : 0;
1763 }
1764