]> git.saurik.com Git - apple/cf.git/blame - CFBasicHash.c
CF-1151.16.tar.gz
[apple/cf.git] / CFBasicHash.c
CommitLineData
cf7d2af9 1/*
d8b101a4 2 * Copyright (c) 2014 Apple Inc. All rights reserved.
cf7d2af9
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
d7384798 5 *
cf7d2af9
A
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.
d7384798 12 *
cf7d2af9
A
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.
d7384798 20 *
cf7d2af9
A
21 * @APPLE_LICENSE_HEADER_END@
22 */
f64f9b69 23
cf7d2af9 24/* CFBasicHash.m
d7384798 25 Copyright (c) 2008-2014, Apple Inc. All rights reserved.
cf7d2af9
A
26 Responsibility: Christopher Kane
27*/
28
29#import "CFBasicHash.h"
30#import <CoreFoundation/CFRuntime.h>
31#import <CoreFoundation/CFSet.h>
32#import <Block.h>
cf7d2af9 33#import <math.h>
a48904a4
A
34#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
35#import <dispatch/dispatch.h>
36#endif
cf7d2af9 37
856091c5 38#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
cf7d2af9 39#define __SetLastAllocationEventName(A, B) do { if (__CFOASafe && (A)) __CFSetLastAllocationEventName(A, B); } while (0)
856091c5
A
40#else
41#define __SetLastAllocationEventName(A, B) do { } while (0)
cf7d2af9
A
42#endif
43
cf7d2af9
A
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
8ca704e1
A
49#if defined(DTRACE_PROBES_DISABLED) && DTRACE_PROBES_DISABLED
50#undef ENABLE_DTRACE_PROBES
51#define ENABLE_DTRACE_PROBES 0
52#endif
cf7d2af9
A
53
54/*
55// dtrace -h -s foo.d
8ca704e1
A
56// Note: output then changed by casts of the arguments
57// dtrace macros last generated 2010-09-08 on 10.7 prerelease (11A259)
cf7d2af9
A
58
59provider 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) \
85do { \
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)
8ca704e1
A
90#define COCOA_HASHTABLE_REHASH_END_ENABLED() \
91 ({ int _r = __dtrace_isenabled$Cocoa_HashTable$rehash_end$v1(); \
92 __asm__ volatile(""); \
93 _r; })
cf7d2af9
A
94#define COCOA_HASHTABLE_REHASH_START(arg0, arg1, arg2) \
95do { \
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)
8ca704e1
A
100#define COCOA_HASHTABLE_REHASH_START_ENABLED() \
101 ({ int _r = __dtrace_isenabled$Cocoa_HashTable$rehash_start$v1(); \
102 __asm__ volatile(""); \
103 _r; })
cf7d2af9
A
104#define COCOA_HASHTABLE_HASH_KEY(arg0, arg1, arg2) \
105do { \
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)
8ca704e1
A
110#define COCOA_HASHTABLE_HASH_KEY_ENABLED() \
111 ({ int _r = __dtrace_isenabled$Cocoa_HashTable$hash_key$v1(); \
112 __asm__ volatile(""); \
113 _r; })
cf7d2af9
A
114#define COCOA_HASHTABLE_PROBE_DELETED(arg0, arg1) \
115do { \
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)
8ca704e1
A
120#define COCOA_HASHTABLE_PROBE_DELETED_ENABLED() \
121 ({ int _r = __dtrace_isenabled$Cocoa_HashTable$probe_deleted$v1(); \
122 __asm__ volatile(""); \
123 _r; })
cf7d2af9
A
124#define COCOA_HASHTABLE_PROBE_EMPTY(arg0, arg1) \
125do { \
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)
8ca704e1
A
130#define COCOA_HASHTABLE_PROBE_EMPTY_ENABLED() \
131 ({ int _r = __dtrace_isenabled$Cocoa_HashTable$probe_empty$v1(); \
132 __asm__ volatile(""); \
133 _r; })
cf7d2af9
A
134#define COCOA_HASHTABLE_PROBE_VALID(arg0, arg1) \
135do { \
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)
8ca704e1
A
140#define COCOA_HASHTABLE_PROBE_VALID_ENABLED() \
141 ({ int _r = __dtrace_isenabled$Cocoa_HashTable$probe_valid$v1(); \
142 __asm__ volatile(""); \
143 _r; })
cf7d2af9
A
144#define COCOA_HASHTABLE_PROBING_END(arg0, arg1) \
145do { \
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)
8ca704e1
A
150#define COCOA_HASHTABLE_PROBING_END_ENABLED() \
151 ({ int _r = __dtrace_isenabled$Cocoa_HashTable$probing_end$v1(); \
152 __asm__ volatile(""); \
153 _r; })
cf7d2af9
A
154#define COCOA_HASHTABLE_PROBING_START(arg0, arg1) \
155do { \
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)
8ca704e1
A
160#define COCOA_HASHTABLE_PROBING_START_ENABLED() \
161 ({ int _r = __dtrace_isenabled$Cocoa_HashTable$probing_start$v1(); \
162 __asm__ volatile(""); \
163 _r; })
cf7d2af9
A
164#define COCOA_HASHTABLE_TEST_EQUAL(arg0, arg1, arg2) \
165do { \
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)
8ca704e1
A
170#define COCOA_HASHTABLE_TEST_EQUAL_ENABLED() \
171 ({ int _r = __dtrace_isenabled$Cocoa_HashTable$test_equal$v1(); \
172 __asm__ volatile(""); \
173 _r; })
cf7d2af9 174
cf7d2af9
A
175extern void __dtrace_probe$Cocoa_HashTable$hash_key$v1$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67(unsigned long, unsigned long, unsigned long);
176extern int __dtrace_isenabled$Cocoa_HashTable$hash_key$v1(void);
177extern void __dtrace_probe$Cocoa_HashTable$probe_deleted$v1$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67(unsigned long, unsigned long);
178extern int __dtrace_isenabled$Cocoa_HashTable$probe_deleted$v1(void);
179extern void __dtrace_probe$Cocoa_HashTable$probe_empty$v1$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67(unsigned long, unsigned long);
180extern int __dtrace_isenabled$Cocoa_HashTable$probe_empty$v1(void);
181extern void __dtrace_probe$Cocoa_HashTable$probe_valid$v1$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67(unsigned long, unsigned long);
182extern int __dtrace_isenabled$Cocoa_HashTable$probe_valid$v1(void);
183extern void __dtrace_probe$Cocoa_HashTable$probing_end$v1$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67(unsigned long, unsigned long);
184extern int __dtrace_isenabled$Cocoa_HashTable$probing_end$v1(void);
185extern void __dtrace_probe$Cocoa_HashTable$probing_start$v1$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67(unsigned long, unsigned long);
186extern int __dtrace_isenabled$Cocoa_HashTable$probing_start$v1(void);
8ca704e1
A
187extern void __dtrace_probe$Cocoa_HashTable$rehash_end$v1$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67(unsigned long, unsigned long, unsigned long);
188extern int __dtrace_isenabled$Cocoa_HashTable$rehash_end$v1(void);
189extern void __dtrace_probe$Cocoa_HashTable$rehash_start$v1$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67(unsigned long, unsigned long, unsigned long);
190extern int __dtrace_isenabled$Cocoa_HashTable$rehash_start$v1(void);
cf7d2af9
A
191extern void __dtrace_probe$Cocoa_HashTable$test_equal$v1$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67(unsigned long, unsigned long, unsigned long);
192extern 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
8ca704e1
A
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.
225static 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,
cf7d2af9 231#if __LP64__
8ca704e1
A
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
243static 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
262static 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
cf7d2af9
A
275#endif
276};
277
8ca704e1
A
278CF_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 }
856091c5
A
286 return new_mem;
287}
288
289CF_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 }
8ca704e1
A
296 return new_mem;
297}
298
299#define __CFBasicHashSubABZero 0xa7baadb1
300#define __CFBasicHashSubABOne 0xa5baadb9
301
cf7d2af9 302typedef union {
8ca704e1 303 uintptr_t neutral;
cf7d2af9 304 id strong;
8ca704e1 305 id weak;
cf7d2af9
A
306} CFBasicHashValue;
307
308struct __CFBasicHash {
309 CFRuntimeBase base;
a48904a4
A
310 struct { // 192 bits
311 uint16_t mutations;
8ca704e1 312 uint8_t hash_style:2;
8ca704e1
A
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;
a48904a4
A
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;
cf7d2af9 341 } bits;
cf7d2af9
A
342 void *pointers[1];
343};
344
a48904a4
A
345static void *CFBasicHashCallBackPtrs[(1UL << 10)];
346static int32_t CFBasicHashCallBackPtrsCount = 0;
cf7d2af9 347
a48904a4
A
348static 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;
cf7d2af9
A
376}
377
a48904a4 378CF_PRIVATE Boolean CFBasicHashHasStrongValues(CFConstBasicHashRef ht) {
856091c5 379#if DEPLOYMENT_TARGET_MACOSX
a48904a4 380 return ht->bits.strong_values ? true : false;
856091c5
A
381#else
382 return false;
8ca704e1 383#endif
cf7d2af9
A
384}
385
a48904a4 386CF_PRIVATE Boolean CFBasicHashHasStrongKeys(CFConstBasicHashRef ht) {
856091c5 387#if DEPLOYMENT_TARGET_MACOSX
a48904a4 388 return ht->bits.strong_keys ? true : false;
856091c5
A
389#else
390 return false;
8ca704e1 391#endif
cf7d2af9
A
392}
393
8ca704e1 394CF_INLINE Boolean __CFBasicHashHasHashCache(CFConstBasicHashRef ht) {
856091c5 395#if DEPLOYMENT_TARGET_MACOSX
8ca704e1 396 return ht->bits.hashes_offset ? true : false;
856091c5
A
397#else
398 return false;
8ca704e1 399#endif
cf7d2af9
A
400}
401
8ca704e1 402CF_INLINE uintptr_t __CFBasicHashImportValue(CFConstBasicHashRef ht, uintptr_t stack_value) {
a48904a4
A
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);
cf7d2af9
A
407}
408
8ca704e1 409CF_INLINE uintptr_t __CFBasicHashImportKey(CFConstBasicHashRef ht, uintptr_t stack_key) {
a48904a4
A
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);
cf7d2af9
A
414}
415
8ca704e1 416CF_INLINE void __CFBasicHashEjectValue(CFConstBasicHashRef ht, uintptr_t stack_value) {
a48904a4
A
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);
cf7d2af9
A
421}
422
8ca704e1 423CF_INLINE void __CFBasicHashEjectKey(CFConstBasicHashRef ht, uintptr_t stack_key) {
a48904a4
A
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
430CF_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
436CF_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);
cf7d2af9
A
440}
441
8ca704e1 442CF_INLINE Boolean __CFBasicHashTestEqualValue(CFConstBasicHashRef ht, uintptr_t stack_value_a, uintptr_t stack_value_b) {
a48904a4
A
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);
cf7d2af9
A
446}
447
8ca704e1
A
448CF_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);
a48904a4
A
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);
cf7d2af9
A
453}
454
8ca704e1 455CF_INLINE CFHashCode __CFBasicHashHashKey(CFConstBasicHashRef ht, uintptr_t stack_key) {
a48904a4
A
456 CFHashCode (*func)(uintptr_t) = (CFHashCode (*)(uintptr_t))CFBasicHashCallBackPtrs[ht->bits.__khas];
457 CFHashCode hash_code = func ? func(stack_key) : stack_key;
8ca704e1
A
458 COCOA_HASHTABLE_HASH_KEY(ht, stack_key, hash_code);
459 return hash_code;
cf7d2af9
A
460}
461
a48904a4
A
462CF_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
8ca704e1
A
468CF_INLINE CFBasicHashValue *__CFBasicHashGetValues(CFConstBasicHashRef ht) {
469 return (CFBasicHashValue *)ht->pointers[0];
cf7d2af9
A
470}
471
8ca704e1
A
472CF_INLINE void __CFBasicHashSetValues(CFBasicHashRef ht, CFBasicHashValue *ptr) {
473 __AssignWithWriteBarrier(&ht->pointers[0], ptr);
cf7d2af9
A
474}
475
8ca704e1
A
476CF_INLINE CFBasicHashValue *__CFBasicHashGetKeys(CFConstBasicHashRef ht) {
477 return (CFBasicHashValue *)ht->pointers[ht->bits.keys_offset];
cf7d2af9
A
478}
479
8ca704e1
A
480CF_INLINE void __CFBasicHashSetKeys(CFBasicHashRef ht, CFBasicHashValue *ptr) {
481 __AssignWithWriteBarrier(&ht->pointers[ht->bits.keys_offset], ptr);
cf7d2af9
A
482}
483
8ca704e1
A
484CF_INLINE void *__CFBasicHashGetCounts(CFConstBasicHashRef ht) {
485 return (void *)ht->pointers[ht->bits.counts_offset];
cf7d2af9
A
486}
487
8ca704e1
A
488CF_INLINE void __CFBasicHashSetCounts(CFBasicHashRef ht, void *ptr) {
489 __AssignWithWriteBarrier(&ht->pointers[ht->bits.counts_offset], ptr);
cf7d2af9
A
490}
491
8ca704e1
A
492CF_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;
cf7d2af9
A
497}
498
8ca704e1
A
499CF_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 }
cf7d2af9
A
514}
515
8ca704e1
A
516CF_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);
a48904a4 525 return __CFBasicHashGetIndirectKey(ht, stack_value);
8ca704e1
A
526 }
527 return __CFBasicHashGetValue(ht, idx);
cf7d2af9
A
528}
529
8ca704e1
A
530CF_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 }
cf7d2af9
A
546}
547
8ca704e1
A
548CF_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);
cf7d2af9
A
551}
552
8ca704e1
A
553CF_INLINE uintptr_t __CFBasicHashIsDeleted(CFConstBasicHashRef ht, CFIndex idx) {
554 uintptr_t stack_value = __CFBasicHashGetValues(ht)[idx].neutral;
555 return (~0UL == stack_value);
cf7d2af9
A
556}
557
8ca704e1
A
558CF_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;
cf7d2af9
A
567}
568
8ca704e1
A
569CF_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);
856091c5 578 if (!counts16) HALT;
8ca704e1
A
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);
856091c5 594 if (!counts32) HALT;
8ca704e1
A
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);
856091c5 610 if (!counts64) HALT;
8ca704e1
A
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 }
cf7d2af9
A
626}
627
8ca704e1
A
628static 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 }
cf7d2af9
A
676}
677
8ca704e1
A
678CF_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;
cf7d2af9 685 }
cf7d2af9
A
686}
687
8ca704e1
A
688CF_INLINE uintptr_t *__CFBasicHashGetHashes(CFConstBasicHashRef ht) {
689 return (uintptr_t *)ht->pointers[ht->bits.hashes_offset];
690}
cf7d2af9 691
8ca704e1
A
692CF_INLINE void __CFBasicHashSetHashes(CFBasicHashRef ht, uintptr_t *ptr) {
693 __AssignWithWriteBarrier(&ht->pointers[ht->bits.hashes_offset], ptr);
694}
cf7d2af9 695
cf7d2af9
A
696
697// to expose the load factor, expose this function to customization
8ca704e1 698CF_INLINE CFIndex __CFBasicHashGetCapacityForNumBuckets(CFConstBasicHashRef ht, CFIndex num_buckets_idx) {
cf7d2af9 699 return __CFBasicHashTableCapacities[num_buckets_idx];
cf7d2af9
A
700}
701
8ca704e1 702CF_INLINE CFIndex __CFBasicHashGetNumBucketsIndexForCapacity(CFConstBasicHashRef ht, CFIndex capacity) {
cf7d2af9
A
703 for (CFIndex idx = 0; idx < 64; idx++) {
704 if (capacity <= __CFBasicHashGetCapacityForNumBuckets(ht, idx)) return idx;
705 }
706 HALT;
707 return 0;
708}
709
a48904a4 710CF_PRIVATE CFIndex CFBasicHashGetNumBuckets(CFConstBasicHashRef ht) {
cf7d2af9
A
711 return __CFBasicHashTableSizes[ht->bits.num_buckets_idx];
712}
713
a48904a4 714CF_PRIVATE CFIndex CFBasicHashGetCapacity(CFConstBasicHashRef ht) {
cf7d2af9
A
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.
a48904a4 723CF_PRIVATE CFBasicHashBucket CFBasicHashGetBucket(CFConstBasicHashRef ht, CFIndex idx) {
cf7d2af9
A
724 CFBasicHashBucket result;
725 result.idx = idx;
8ca704e1
A
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 }
cf7d2af9
A
735 return result;
736}
737
8ca704e1
A
738#if defined(__arm__)
739static 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;
cf7d2af9 780 }
8ca704e1
A
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
860CF_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;
cf7d2af9 864 }
8ca704e1
A
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);
cf7d2af9 876 }
cf7d2af9 877 }
8ca704e1
A
878 HALT;
879 CFBasicHashBucket result = {kCFNotFound, 0UL, 0UL, 0};
880 return result;
cf7d2af9
A
881}
882
8ca704e1
A
883CF_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 }
cf7d2af9
A
899 }
900 HALT;
8ca704e1 901 return kCFNotFound;
cf7d2af9
A
902}
903
a48904a4 904CF_PRIVATE CFBasicHashBucket CFBasicHashFindBucket(CFConstBasicHashRef ht, uintptr_t stack_key) {
8ca704e1
A
905 if (__CFBasicHashSubABZero == stack_key || __CFBasicHashSubABOne == stack_key) {
906 CFBasicHashBucket result = {kCFNotFound, 0UL, 0UL, 0};
cf7d2af9
A
907 return result;
908 }
8ca704e1 909 return __CFBasicHashFindBucket(ht, stack_key);
cf7d2af9
A
910}
911
a48904a4
A
912CF_PRIVATE void CFBasicHashSuppressRC(CFBasicHashRef ht) {
913 ht->bits.null_rc = 1;
cf7d2af9
A
914}
915
a48904a4
A
916CF_PRIVATE void CFBasicHashUnsuppressRC(CFBasicHashRef ht) {
917 ht->bits.null_rc = 0;
8ca704e1
A
918}
919
a48904a4 920CF_PRIVATE CFOptionFlags CFBasicHashGetFlags(CFConstBasicHashRef ht) {
cf7d2af9 921 CFOptionFlags flags = (ht->bits.hash_style << 13);
8ca704e1
A
922 if (CFBasicHashHasStrongValues(ht)) flags |= kCFBasicHashStrongValues;
923 if (CFBasicHashHasStrongKeys(ht)) flags |= kCFBasicHashStrongKeys;
cf7d2af9 924 if (ht->bits.fast_grow) flags |= kCFBasicHashAggressiveGrowth;
cf7d2af9 925 if (ht->bits.keys_offset) flags |= kCFBasicHashHasKeys;
cf7d2af9 926 if (ht->bits.counts_offset) flags |= kCFBasicHashHasCounts;
8ca704e1 927 if (__CFBasicHashHasHashCache(ht)) flags |= kCFBasicHashHasHashCache;
cf7d2af9
A
928 return flags;
929}
930
a48904a4 931CF_PRIVATE CFIndex CFBasicHashGetCount(CFConstBasicHashRef ht) {
8ca704e1 932 if (ht->bits.counts_offset) {
cf7d2af9
A
933 CFIndex total = 0L;
934 CFIndex cnt = (CFIndex)__CFBasicHashTableSizes[ht->bits.num_buckets_idx];
cf7d2af9 935 for (CFIndex idx = 0; idx < cnt; idx++) {
8ca704e1 936 total += __CFBasicHashGetSlotCount(ht, idx);
cf7d2af9
A
937 }
938 return total;
939 }
940 return (CFIndex)ht->bits.used_buckets;
941}
942
a48904a4 943CF_PRIVATE CFIndex CFBasicHashGetCountOfKey(CFConstBasicHashRef ht, uintptr_t stack_key) {
8ca704e1
A
944 if (__CFBasicHashSubABZero == stack_key || __CFBasicHashSubABOne == stack_key) {
945 return 0L;
946 }
cf7d2af9
A
947 if (0L == ht->bits.used_buckets) {
948 return 0L;
949 }
950 return __CFBasicHashFindBucket(ht, stack_key).count;
951}
952
a48904a4 953CF_PRIVATE CFIndex CFBasicHashGetCountOfValue(CFConstBasicHashRef ht, uintptr_t stack_value) {
8ca704e1
A
954 if (__CFBasicHashSubABZero == stack_value) {
955 return 0L;
956 }
cf7d2af9
A
957 if (0L == ht->bits.used_buckets) {
958 return 0L;
959 }
8ca704e1 960 if (!(ht->bits.keys_offset)) {
cf7d2af9
A
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
a48904a4 971CF_PRIVATE Boolean CFBasicHashesAreEqual(CFConstBasicHashRef ht1, CFConstBasicHashRef ht2) {
cf7d2af9
A
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 }
8ca704e1 982 if ((ht1->bits.keys_offset) && (bkt1.weak_value != bkt2.weak_value) && !__CFBasicHashTestEqualValue(ht1, bkt1.weak_value, bkt2.weak_value)) {
cf7d2af9
A
983 equal = false;
984 return (Boolean)false;
985 }
986 return (Boolean)true;
987 });
988 return equal;
989}
990
a48904a4 991CF_PRIVATE void CFBasicHashApply(CFConstBasicHashRef ht, Boolean (^block)(CFBasicHashBucket)) {
cf7d2af9
A
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
a48904a4 1004CF_PRIVATE void CFBasicHashApplyIndexed(CFConstBasicHashRef ht, CFRange range, Boolean (^block)(CFBasicHashBucket)) {
8ca704e1
A
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
a48904a4 1019CF_PRIVATE void CFBasicHashGetElements(CFConstBasicHashRef ht, CFIndex bufferslen, uintptr_t *weak_values, uintptr_t *weak_keys) {
cf7d2af9 1020 CFIndex used = (CFIndex)ht->bits.used_buckets, cnt = (CFIndex)__CFBasicHashTableSizes[ht->bits.num_buckets_idx];
cf7d2af9
A
1021 CFIndex offset = 0;
1022 for (CFIndex idx = 0; 0 < used && idx < cnt && offset < bufferslen; idx++) {
8ca704e1
A
1023 CFBasicHashBucket bkt = CFBasicHashGetBucket(ht, idx);
1024 if (0 < bkt.count) {
cf7d2af9 1025 used--;
8ca704e1
A
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; }
cf7d2af9
A
1029 offset++;
1030 }
1031 }
1032 }
1033}
1034
a48904a4 1035CF_PRIVATE unsigned long __CFBasicHashFastEnumeration(CFConstBasicHashRef ht, struct __objcFastEnumerationStateEquivalent2 *state, void *stackbuffer, unsigned long count) {
cf7d2af9
A
1036 /* copy as many as count items over */
1037 if (0 == state->state) { /* first time */
a48904a4 1038 state->mutationsPtr = (unsigned long *)&ht->bits;
cf7d2af9
A
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
1055static volatile int64_t __CFBasicHashTotalCount = 0ULL;
1056static volatile int64_t __CFBasicHashTotalSize = 0ULL;
1057static volatile int64_t __CFBasicHashPeakCount = 0ULL;
1058static volatile int64_t __CFBasicHashPeakSize = 0ULL;
1059static volatile int32_t __CFBasicHashSizes[64] = {0};
1060#endif
1061
1062static void __CFBasicHashDrain(CFBasicHashRef ht, Boolean forFinalization) {
1063#if ENABLE_MEMORY_COUNTERS
1064 OSAtomicAdd64Barrier(-1 * (int64_t) CFBasicHashGetSize(ht, true), & __CFBasicHashTotalSize);
1065#endif
1066
cf7d2af9
A
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
8ca704e1
A
1072 CFBasicHashValue *old_values = NULL, *old_keys = NULL;
1073 void *old_counts = NULL;
1074 uintptr_t *old_hashes = NULL;
cf7d2af9
A
1075
1076 old_values = __CFBasicHashGetValues(ht);
1077 if (nullify) __CFBasicHashSetValues(ht, NULL);
8ca704e1 1078 if (ht->bits.keys_offset) {
cf7d2af9
A
1079 old_keys = __CFBasicHashGetKeys(ht);
1080 if (nullify) __CFBasicHashSetKeys(ht, NULL);
1081 }
8ca704e1 1082 if (ht->bits.counts_offset) {
cf7d2af9
A
1083 old_counts = __CFBasicHashGetCounts(ht);
1084 if (nullify) __CFBasicHashSetCounts(ht, NULL);
1085 }
8ca704e1 1086 if (__CFBasicHashHasHashCache(ht)) {
cf7d2af9
A
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;
cf7d2af9
A
1095 ht->bits.deleted = 0;
1096 }
1097
cf7d2af9 1098 for (CFIndex idx = 0; idx < old_num_buckets; idx++) {
8ca704e1
A
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);
cf7d2af9 1105 if (old_keys) {
8ca704e1
A
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);
cf7d2af9
A
1110 }
1111 }
1112 }
cf7d2af9 1113
cf7d2af9
A
1114 if (!CF_IS_COLLECTABLE_ALLOCATOR(allocator)) {
1115 CFAllocatorDeallocate(allocator, old_values);
cf7d2af9 1116 CFAllocatorDeallocate(allocator, old_keys);
cf7d2af9 1117 CFAllocatorDeallocate(allocator, old_counts);
cf7d2af9
A
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
1127static 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
8ca704e1
A
1148 CFBasicHashValue *new_values = NULL, *new_keys = NULL;
1149 void *new_counts = NULL;
1150 uintptr_t *new_hashes = NULL;
cf7d2af9
A
1151
1152 if (0 < new_num_buckets) {
a48904a4 1153 new_values = (CFBasicHashValue *)__CFBasicHashAllocateMemory(ht, new_num_buckets, sizeof(CFBasicHashValue), CFBasicHashHasStrongValues(ht), 0);
856091c5 1154 if (!new_values) HALT;
cf7d2af9 1155 __SetLastAllocationEventName(new_values, "CFBasicHash (value-store)");
8ca704e1
A
1156 memset(new_values, 0, new_num_buckets * sizeof(CFBasicHashValue));
1157 if (ht->bits.keys_offset) {
a48904a4 1158 new_keys = (CFBasicHashValue *)__CFBasicHashAllocateMemory(ht, new_num_buckets, sizeof(CFBasicHashValue), CFBasicHashHasStrongKeys(ht), 0);
856091c5 1159 if (!new_keys) HALT;
cf7d2af9 1160 __SetLastAllocationEventName(new_keys, "CFBasicHash (key-store)");
8ca704e1 1161 memset(new_keys, 0, new_num_buckets * sizeof(CFBasicHashValue));
cf7d2af9 1162 }
8ca704e1
A
1163 if (ht->bits.counts_offset) {
1164 new_counts = (uintptr_t *)__CFBasicHashAllocateMemory(ht, new_num_buckets, (1 << ht->bits.counts_width), false, false);
856091c5 1165 if (!new_counts) HALT;
cf7d2af9 1166 __SetLastAllocationEventName(new_counts, "CFBasicHash (count-store)");
8ca704e1 1167 memset(new_counts, 0, new_num_buckets * (1 << ht->bits.counts_width));
cf7d2af9 1168 }
8ca704e1
A
1169 if (__CFBasicHashHasHashCache(ht)) {
1170 new_hashes = (uintptr_t *)__CFBasicHashAllocateMemory(ht, new_num_buckets, sizeof(uintptr_t), false, false);
856091c5 1171 if (!new_hashes) HALT;
cf7d2af9
A
1172 __SetLastAllocationEventName(new_hashes, "CFBasicHash (hash-store)");
1173 memset(new_hashes, 0, new_num_buckets * sizeof(uintptr_t));
1174 }
1175 }
1176
cf7d2af9
A
1177 ht->bits.num_buckets_idx = new_num_buckets_idx;
1178 ht->bits.deleted = 0;
1179
8ca704e1
A
1180 CFBasicHashValue *old_values = NULL, *old_keys = NULL;
1181 void *old_counts = NULL;
1182 uintptr_t *old_hashes = NULL;
cf7d2af9
A
1183
1184 old_values = __CFBasicHashGetValues(ht);
1185 __CFBasicHashSetValues(ht, new_values);
8ca704e1 1186 if (ht->bits.keys_offset) {
cf7d2af9
A
1187 old_keys = __CFBasicHashGetKeys(ht);
1188 __CFBasicHashSetKeys(ht, new_keys);
1189 }
8ca704e1 1190 if (ht->bits.counts_offset) {
cf7d2af9
A
1191 old_counts = __CFBasicHashGetCounts(ht);
1192 __CFBasicHashSetCounts(ht, new_counts);
1193 }
8ca704e1 1194 if (__CFBasicHashHasHashCache(ht)) {
cf7d2af9
A
1195 old_hashes = __CFBasicHashGetHashes(ht);
1196 __CFBasicHashSetHashes(ht, new_hashes);
1197 }
1198
1199 if (0 < old_num_buckets) {
cf7d2af9 1200 for (CFIndex idx = 0; idx < old_num_buckets; idx++) {
8ca704e1
A
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;
cf7d2af9 1210 }
8ca704e1 1211 if (ht->bits.indirect_keys) {
a48904a4 1212 stack_key = __CFBasicHashGetIndirectKey(ht, stack_value);
cf7d2af9 1213 }
8ca704e1
A
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);
cf7d2af9
A
1218 }
1219 if (old_counts) {
8ca704e1
A
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 }
cf7d2af9
A
1226 }
1227 if (old_hashes) {
8ca704e1 1228 new_hashes[bkt_idx] = old_hashes[idx];
cf7d2af9
A
1229 }
1230 }
1231 }
1232 }
1233
1234 CFAllocatorRef allocator = CFGetAllocator(ht);
1235 if (!CF_IS_COLLECTABLE_ALLOCATOR(allocator)) {
1236 CFAllocatorDeallocate(allocator, old_values);
cf7d2af9 1237 CFAllocatorDeallocate(allocator, old_keys);
cf7d2af9 1238 CFAllocatorDeallocate(allocator, old_counts);
cf7d2af9
A
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
a48904a4 1251CF_PRIVATE void CFBasicHashSetCapacity(CFBasicHashRef ht, CFIndex capacity) {
cf7d2af9
A
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
8ca704e1 1259static void __CFBasicHashAddValue(CFBasicHashRef ht, CFIndex bkt_idx, uintptr_t stack_key, uintptr_t stack_value) {
cf7d2af9 1260 ht->bits.mutations++;
cf7d2af9
A
1261 if (CFBasicHashGetCapacity(ht) < ht->bits.used_buckets + 1) {
1262 __CFBasicHashRehash(ht, 1);
8ca704e1
A
1263 bkt_idx = __CFBasicHashFindBucket_NoCollision(ht, stack_key, 0);
1264 } else if (__CFBasicHashIsDeleted(ht, bkt_idx)) {
cf7d2af9
A
1265 ht->bits.deleted--;
1266 }
8ca704e1
A
1267 uintptr_t key_hash = 0;
1268 if (__CFBasicHashHasHashCache(ht)) {
1269 key_hash = __CFBasicHashHashKey(ht, stack_key);
cf7d2af9 1270 }
8ca704e1
A
1271 stack_value = __CFBasicHashImportValue(ht, stack_value);
1272 if (ht->bits.keys_offset) {
1273 stack_key = __CFBasicHashImportKey(ht, stack_key);
cf7d2af9 1274 }
8ca704e1
A
1275 __CFBasicHashSetValue(ht, bkt_idx, stack_value, false, false);
1276 if (ht->bits.keys_offset) {
1277 __CFBasicHashSetKey(ht, bkt_idx, stack_key, false, false);
cf7d2af9 1278 }
8ca704e1
A
1279 if (ht->bits.counts_offset) {
1280 __CFBasicHashIncSlotCount(ht, bkt_idx);
cf7d2af9 1281 }
8ca704e1
A
1282 if (__CFBasicHashHasHashCache(ht)) {
1283 __CFBasicHashGetHashes(ht)[bkt_idx] = key_hash;
cf7d2af9
A
1284 }
1285 ht->bits.used_buckets++;
1286}
1287
8ca704e1 1288static void __CFBasicHashReplaceValue(CFBasicHashRef ht, CFIndex bkt_idx, uintptr_t stack_key, uintptr_t stack_value) {
cf7d2af9
A
1289 ht->bits.mutations++;
1290 stack_value = __CFBasicHashImportValue(ht, stack_value);
8ca704e1 1291 if (ht->bits.keys_offset) {
cf7d2af9 1292 stack_key = __CFBasicHashImportKey(ht, stack_key);
cf7d2af9 1293 }
8ca704e1
A
1294 __CFBasicHashSetValue(ht, bkt_idx, stack_value, false, false);
1295 if (ht->bits.keys_offset) {
1296 __CFBasicHashSetKey(ht, bkt_idx, stack_key, false, false);
cf7d2af9
A
1297 }
1298}
1299
8ca704e1 1300static void __CFBasicHashRemoveValue(CFBasicHashRef ht, CFIndex bkt_idx) {
cf7d2af9 1301 ht->bits.mutations++;
8ca704e1
A
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;
cf7d2af9
A
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
a48904a4 1332CF_PRIVATE Boolean CFBasicHashAddValue(CFBasicHashRef ht, uintptr_t stack_key, uintptr_t stack_value) {
cf7d2af9 1333 if (!CFBasicHashIsMutable(ht)) HALT;
8ca704e1
A
1334 if (__CFBasicHashSubABZero == stack_key) HALT;
1335 if (__CFBasicHashSubABOne == stack_key) HALT;
1336 if (__CFBasicHashSubABZero == stack_value) HALT;
1337 if (__CFBasicHashSubABOne == stack_value) HALT;
cf7d2af9
A
1338 CFBasicHashBucket bkt = __CFBasicHashFindBucket(ht, stack_key);
1339 if (0 < bkt.count) {
1340 ht->bits.mutations++;
8ca704e1
A
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;
cf7d2af9
A
1344 }
1345 } else {
8ca704e1
A
1346 __CFBasicHashAddValue(ht, bkt.idx, stack_key, stack_value);
1347 return true;
cf7d2af9 1348 }
8ca704e1 1349 return false;
cf7d2af9
A
1350}
1351
a48904a4 1352CF_PRIVATE void CFBasicHashReplaceValue(CFBasicHashRef ht, uintptr_t stack_key, uintptr_t stack_value) {
cf7d2af9 1353 if (!CFBasicHashIsMutable(ht)) HALT;
8ca704e1
A
1354 if (__CFBasicHashSubABZero == stack_key) HALT;
1355 if (__CFBasicHashSubABOne == stack_key) HALT;
1356 if (__CFBasicHashSubABZero == stack_value) HALT;
1357 if (__CFBasicHashSubABOne == stack_value) HALT;
cf7d2af9
A
1358 CFBasicHashBucket bkt = __CFBasicHashFindBucket(ht, stack_key);
1359 if (0 < bkt.count) {
8ca704e1 1360 __CFBasicHashReplaceValue(ht, bkt.idx, stack_key, stack_value);
cf7d2af9
A
1361 }
1362}
1363
a48904a4 1364CF_PRIVATE void CFBasicHashSetValue(CFBasicHashRef ht, uintptr_t stack_key, uintptr_t stack_value) {
cf7d2af9 1365 if (!CFBasicHashIsMutable(ht)) HALT;
8ca704e1
A
1366 if (__CFBasicHashSubABZero == stack_key) HALT;
1367 if (__CFBasicHashSubABOne == stack_key) HALT;
1368 if (__CFBasicHashSubABZero == stack_value) HALT;
1369 if (__CFBasicHashSubABOne == stack_value) HALT;
cf7d2af9
A
1370 CFBasicHashBucket bkt = __CFBasicHashFindBucket(ht, stack_key);
1371 if (0 < bkt.count) {
8ca704e1 1372 __CFBasicHashReplaceValue(ht, bkt.idx, stack_key, stack_value);
cf7d2af9 1373 } else {
8ca704e1 1374 __CFBasicHashAddValue(ht, bkt.idx, stack_key, stack_value);
cf7d2af9
A
1375 }
1376}
1377
a48904a4 1378CF_PRIVATE CFIndex CFBasicHashRemoveValue(CFBasicHashRef ht, uintptr_t stack_key) {
cf7d2af9 1379 if (!CFBasicHashIsMutable(ht)) HALT;
8ca704e1 1380 if (__CFBasicHashSubABZero == stack_key || __CFBasicHashSubABOne == stack_key) return 0;
cf7d2af9
A
1381 CFBasicHashBucket bkt = __CFBasicHashFindBucket(ht, stack_key);
1382 if (1 < bkt.count) {
1383 ht->bits.mutations++;
8ca704e1
A
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);
cf7d2af9
A
1386 }
1387 } else if (0 < bkt.count) {
8ca704e1
A
1388 __CFBasicHashRemoveValue(ht, bkt.idx);
1389 }
1390 return bkt.count;
1391}
1392
a48904a4 1393CF_PRIVATE CFIndex CFBasicHashRemoveValueAtIndex(CFBasicHashRef ht, CFIndex idx) {
8ca704e1
A
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);
cf7d2af9
A
1403 }
1404 return bkt.count;
1405}
1406
a48904a4 1407CF_PRIVATE void CFBasicHashRemoveAllValues(CFBasicHashRef ht) {
cf7d2af9
A
1408 if (!CFBasicHashIsMutable(ht)) HALT;
1409 if (0 == ht->bits.num_buckets_idx) return;
1410 __CFBasicHashDrain(ht, false);
1411}
1412
a48904a4 1413CF_PRIVATE Boolean CFBasicHashAddIntValueAndInc(CFBasicHashRef ht, uintptr_t stack_key, uintptr_t int_value) {
8ca704e1
A
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
a48904a4 1445CF_PRIVATE void CFBasicHashRemoveIntValueAndDec(CFBasicHashRef ht, uintptr_t int_value) {
8ca704e1
A
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
a48904a4 1467CF_PRIVATE size_t CFBasicHashGetSize(CFConstBasicHashRef ht, Boolean total) {
cf7d2af9 1468 size_t size = sizeof(struct __CFBasicHash);
8ca704e1
A
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 *);
cf7d2af9
A
1472 if (total) {
1473 CFIndex num_buckets = __CFBasicHashTableSizes[ht->bits.num_buckets_idx];
1474 if (0 < num_buckets) {
1475 size += malloc_size(__CFBasicHashGetValues(ht));
8ca704e1
A
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));
cf7d2af9
A
1479 }
1480 }
1481 return size;
1482}
1483
a48904a4 1484CF_PRIVATE CFStringRef CFBasicHashCopyDescription(CFConstBasicHashRef ht, Boolean detailed, CFStringRef prefix, CFStringRef entryPrefix, Boolean describeElements) {
cf7d2af9 1485 CFMutableStringRef result = CFStringCreateMutable(kCFAllocatorSystemDefault, 0);
8ca704e1 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));
cf7d2af9
A
1487 if (detailed) {
1488 const char *cb_type = "custom";
8ca704e1 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);
a48904a4 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);
8ca704e1 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"));
a48904a4 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));
8ca704e1 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));
cf7d2af9
A
1494 }
1495 CFStringAppendFormat(result, NULL, CFSTR("%@entries =>\n"), prefix);
1496 CFBasicHashApply(ht, ^(CFBasicHashBucket bkt) {
1497 CFStringRef vDesc = NULL, kDesc = NULL;
8ca704e1
A
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 {
a48904a4 1504 vDesc = __CFBasicHashDescValue(ht, bkt.weak_value);
8ca704e1 1505 if (ht->bits.keys_offset) {
a48904a4 1506 kDesc = __CFBasicHashDescKey(ht, bkt.weak_key);
8ca704e1 1507 }
cf7d2af9 1508 }
8ca704e1 1509 if (ht->bits.keys_offset && ht->bits.counts_offset) {
cf7d2af9 1510 CFStringAppendFormat(result, NULL, CFSTR("%@%ld : %@ = %@ (%ld)\n"), entryPrefix, bkt.idx, kDesc, vDesc, bkt.count);
8ca704e1 1511 } else if (ht->bits.keys_offset) {
cf7d2af9 1512 CFStringAppendFormat(result, NULL, CFSTR("%@%ld : %@ = %@\n"), entryPrefix, bkt.idx, kDesc, vDesc);
8ca704e1 1513 } else if (ht->bits.counts_offset) {
cf7d2af9
A
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
a48904a4 1526CF_PRIVATE void CFBasicHashShow(CFConstBasicHashRef ht) {
cf7d2af9
A
1527 CFStringRef str = CFBasicHashCopyDescription(ht, true, CFSTR(""), CFSTR("\t"), false);
1528 CFShow(str);
1529 CFRelease(str);
1530}
1531
a48904a4 1532CF_PRIVATE Boolean __CFBasicHashEqual(CFTypeRef cf1, CFTypeRef cf2) {
cf7d2af9
A
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
a48904a4 1539CF_PRIVATE CFHashCode __CFBasicHashHash(CFTypeRef cf) {
cf7d2af9
A
1540 CFBasicHashRef ht = (CFBasicHashRef)cf;
1541 return CFBasicHashGetCount(ht);
1542}
1543
a48904a4 1544CF_PRIVATE CFStringRef __CFBasicHashCopyDescription(CFTypeRef cf) {
cf7d2af9
A
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
a48904a4 1552CF_PRIVATE void __CFBasicHashDeallocate(CFTypeRef cf) {
cf7d2af9
A
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
1563static CFTypeID __kCFBasicHashTypeID = _kCFRuntimeNotATypeID;
1564
1565static 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
a48904a4 1577CF_PRIVATE CFTypeID CFBasicHashGetTypeID(void) {
d7384798
A
1578 static dispatch_once_t initOnce;
1579 dispatch_once(&initOnce, ^{ __kCFBasicHashTypeID = _CFRuntimeRegisterClass(&__CFBasicHashClass); });
cf7d2af9
A
1580 return __kCFBasicHashTypeID;
1581}
1582
a48904a4 1583CF_PRIVATE CFBasicHashRef CFBasicHashCreate(CFAllocatorRef allocator, CFOptionFlags flags, const CFBasicHashCallbacks *cb) {
cf7d2af9 1584 size_t size = sizeof(struct __CFBasicHash) - sizeof(CFRuntimeBase);
cf7d2af9 1585 if (flags & kCFBasicHashHasKeys) size += sizeof(CFBasicHashValue *); // keys
8ca704e1 1586 if (flags & kCFBasicHashHasCounts) size += sizeof(void *); // counts
cf7d2af9
A
1587 if (flags & kCFBasicHashHasHashCache) size += sizeof(uintptr_t *); // hashes
1588 CFBasicHashRef ht = (CFBasicHashRef)_CFRuntimeCreateInstance(allocator, CFBasicHashGetTypeID(), size, NULL);
856091c5 1589 if (NULL == ht) return NULL;
cf7d2af9
A
1590
1591 ht->bits.finalized = 0;
cf7d2af9
A
1592 ht->bits.hash_style = (flags >> 13) & 0x3;
1593 ht->bits.fast_grow = (flags & kCFBasicHashAggressiveGrowth) ? 1 : 0;
8ca704e1
A
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;
cf7d2af9
A
1602 ht->bits.num_buckets_idx = 0;
1603 ht->bits.used_buckets = 0;
cf7d2af9
A
1604 ht->bits.deleted = 0;
1605 ht->bits.mutations = 1;
1606
8ca704e1
A
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
cf7d2af9 1617 uint64_t offset = 1;
cf7d2af9 1618 ht->bits.keys_offset = (flags & kCFBasicHashHasKeys) ? offset++ : 0;
cf7d2af9 1619 ht->bits.counts_offset = (flags & kCFBasicHashHasCounts) ? offset++ : 0;
cf7d2af9
A
1620 ht->bits.hashes_offset = (flags & kCFBasicHashHasHashCache) ? offset++ : 0;
1621
856091c5 1622#if DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
8ca704e1
A
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
a48904a4
A
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
cf7d2af9
A
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
a48904a4 1656CF_PRIVATE CFBasicHashRef CFBasicHashCreateCopy(CFAllocatorRef allocator, CFConstBasicHashRef src_ht) {
cf7d2af9 1657 size_t size = CFBasicHashGetSize(src_ht, false) - sizeof(CFRuntimeBase);
856091c5
A
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));
a48904a4 1666 new_values = (CFBasicHashValue *)__CFBasicHashAllocateMemory2(allocator, new_num_buckets, sizeof(CFBasicHashValue), strongValues, 0);
856091c5
A
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
cf7d2af9 1686 CFBasicHashRef ht = (CFBasicHashRef)_CFRuntimeCreateInstance(allocator, CFBasicHashGetTypeID(), size, NULL);
856091c5 1687 if (NULL == ht) return NULL; // in this unusual circumstance, leak previously allocated blocks for now
cf7d2af9
A
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;
cf7d2af9 1692 ht->bits.strong_keys = 0;
8ca704e1
A
1693 ht->bits.weak_values = 0;
1694 ht->bits.weak_keys = 0;
cf7d2af9
A
1695 }
1696 ht->bits.finalized = 0;
1697 ht->bits.mutations = 1;
cf7d2af9 1698
cf7d2af9
A
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
8ca704e1
A
1710 CFBasicHashValue *old_values = NULL, *old_keys = NULL;
1711 void *old_counts = NULL;
1712 uintptr_t *old_hashes = NULL;
1713
cf7d2af9 1714 old_values = __CFBasicHashGetValues(src_ht);
8ca704e1 1715 if (src_ht->bits.keys_offset) {
cf7d2af9
A
1716 old_keys = __CFBasicHashGetKeys(src_ht);
1717 }
8ca704e1 1718 if (src_ht->bits.counts_offset) {
cf7d2af9
A
1719 old_counts = __CFBasicHashGetCounts(src_ht);
1720 }
8ca704e1 1721 if (__CFBasicHashHasHashCache(src_ht)) {
cf7d2af9
A
1722 old_hashes = __CFBasicHashGetHashes(src_ht);
1723 }
1724
cf7d2af9 1725 __CFBasicHashSetValues(ht, new_values);
cf7d2af9
A
1726 if (new_keys) {
1727 __CFBasicHashSetKeys(ht, new_keys);
1728 }
cf7d2af9
A
1729 if (new_counts) {
1730 __CFBasicHashSetCounts(ht, new_counts);
1731 }
cf7d2af9
A
1732 if (new_hashes) {
1733 __CFBasicHashSetHashes(ht, new_hashes);
1734 }
1735
8ca704e1
A
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
cf7d2af9
A
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
cf7d2af9 1770