1/*
2 * Copyright (c) 2014 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/*	CFBag.c
25	Copyright (c) 1998-2013, Apple Inc. All rights reserved.
26	Responsibility: Christopher Kane
27	Machine generated from Notes/HashingCode.template
28*/
29
30
31
32
33
34#include <CoreFoundation/CFBag.h>
35#include "CFInternal.h"
36#include "CFBasicHash.h"
37#include <CoreFoundation/CFString.h>
38
39
40#define CFDictionary 0
41#define CFSet 0
42#define CFBag 0
43#undef CFBag
44#define CFBag 1
45
46#if CFDictionary
47const CFBagKeyCallBacks kCFTypeBagKeyCallBacks = {0, __CFTypeCollectionRetain, __CFTypeCollectionRelease, CFCopyDescription, CFEqual, CFHash};
48const CFBagKeyCallBacks kCFCopyStringBagKeyCallBacks = {0, __CFStringCollectionCopy, __CFTypeCollectionRelease, CFCopyDescription, CFEqual, CFHash};
49const CFBagValueCallBacks kCFTypeBagValueCallBacks = {0, __CFTypeCollectionRetain, __CFTypeCollectionRelease, CFCopyDescription, CFEqual};
50static const CFBagKeyCallBacks __kCFNullBagKeyCallBacks = {0, NULL, NULL, NULL, NULL, NULL};
51static const CFBagValueCallBacks __kCFNullBagValueCallBacks = {0, NULL, NULL, NULL, NULL};
52
53#define CFHashRef CFDictionaryRef
54#define CFMutableHashRef CFMutableDictionaryRef
55#define CFHashKeyCallBacks CFBagKeyCallBacks
56#define CFHashValueCallBacks CFBagValueCallBacks
57#endif
58
59#if CFSet
60const CFBagCallBacks kCFTypeBagCallBacks = {0, __CFTypeCollectionRetain, __CFTypeCollectionRelease, CFCopyDescription, CFEqual, CFHash};
61const CFBagCallBacks kCFCopyStringBagCallBacks = {0, __CFStringCollectionCopy, __CFTypeCollectionRelease, CFCopyDescription, CFEqual, CFHash};
62static const CFBagCallBacks __kCFNullBagCallBacks = {0, NULL, NULL, NULL, NULL, NULL};
63
64#define CFBagKeyCallBacks CFBagCallBacks
65#define CFBagValueCallBacks CFBagCallBacks
66#define kCFTypeBagKeyCallBacks kCFTypeBagCallBacks
67#define kCFTypeBagValueCallBacks kCFTypeBagCallBacks
68#define __kCFNullBagKeyCallBacks __kCFNullBagCallBacks
69#define __kCFNullBagValueCallBacks __kCFNullBagCallBacks
70
71#define CFHashRef CFSetRef
72#define CFMutableHashRef CFMutableSetRef
73#define CFHashKeyCallBacks CFBagCallBacks
74#define CFHashValueCallBacks CFBagCallBacks
75#endif
76
77#if CFBag
78const CFBagCallBacks kCFTypeBagCallBacks = {0, __CFTypeCollectionRetain, __CFTypeCollectionRelease, CFCopyDescription, CFEqual, CFHash};
79const CFBagCallBacks kCFCopyStringBagCallBacks = {0, __CFStringCollectionCopy, __CFTypeCollectionRelease, CFCopyDescription, CFEqual, CFHash};
80static const CFBagCallBacks __kCFNullBagCallBacks = {0, NULL, NULL, NULL, NULL, NULL};
81
82#define CFBagKeyCallBacks CFBagCallBacks
83#define CFBagValueCallBacks CFBagCallBacks
84#define kCFTypeBagKeyCallBacks kCFTypeBagCallBacks
85#define kCFTypeBagValueCallBacks kCFTypeBagCallBacks
86#define __kCFNullBagKeyCallBacks __kCFNullBagCallBacks
87#define __kCFNullBagValueCallBacks __kCFNullBagCallBacks
88
89#define CFHashRef CFBagRef
90#define CFMutableHashRef CFMutableBagRef
91#define CFHashKeyCallBacks CFBagCallBacks
92#define CFHashValueCallBacks CFBagCallBacks
93#endif
94
95
96typedef uintptr_t any_t;
97typedef const void * const_any_pointer_t;
98typedef void * any_pointer_t;
99
100static Boolean __CFBagEqual(CFTypeRef cf1, CFTypeRef cf2) {
101    return __CFBasicHashEqual((CFBasicHashRef)cf1, (CFBasicHashRef)cf2);
102}
103
104static CFHashCode __CFBagHash(CFTypeRef cf) {
105    return __CFBasicHashHash((CFBasicHashRef)cf);
106}
107
108static CFStringRef __CFBagCopyDescription(CFTypeRef cf) {
109    return __CFBasicHashCopyDescription((CFBasicHashRef)cf);
110}
111
112static void __CFBagDeallocate(CFTypeRef cf) {
113    __CFBasicHashDeallocate((CFBasicHashRef)cf);
114}
115
116static CFTypeID __kCFBagTypeID = _kCFRuntimeNotATypeID;
117
118static const CFRuntimeClass __CFBagClass = {
119    _kCFRuntimeScannedObject,
120    "CFBag",
121    NULL,        // init
122    NULL,        // copy
123    __CFBagDeallocate,
124    __CFBagEqual,
125    __CFBagHash,
126    NULL,        //
127    __CFBagCopyDescription
128};
129
130CFTypeID CFBagGetTypeID(void) {
131    if (_kCFRuntimeNotATypeID == __kCFBagTypeID) __kCFBagTypeID = _CFRuntimeRegisterClass(&__CFBagClass);
132    return __kCFBagTypeID;
133}
134
135
136static CFBasicHashRef __CFBagCreateGeneric(CFAllocatorRef allocator, const CFHashKeyCallBacks *keyCallBacks, const CFHashValueCallBacks *valueCallBacks, Boolean useValueCB) {
137    CFOptionFlags flags = kCFBasicHashLinearHashing; // kCFBasicHashExponentialHashing
138    flags |= (CFDictionary ? kCFBasicHashHasKeys : 0) | (CFBag ? kCFBasicHashHasCounts : 0);
139
140    if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { // all this crap is just for figuring out two flags for GC in the way done historically; it probably simplifies down to three lines, but we let the compiler worry about that
141        Boolean set_cb = false;
142        Boolean std_cb = false;
143        const_any_pointer_t (*key_retain)(CFAllocatorRef, const_any_pointer_t) = NULL;
144        void (*key_release)(CFAllocatorRef, const_any_pointer_t) = NULL;
145        const_any_pointer_t (*value_retain)(CFAllocatorRef, const_any_pointer_t) = NULL;
146        void (*value_release)(CFAllocatorRef, const_any_pointer_t) = NULL;
147
148	if ((NULL == keyCallBacks || 0 == keyCallBacks->version) && (!useValueCB || NULL == valueCallBacks || 0 == valueCallBacks->version)) {
149	    Boolean keyRetainNull = NULL == keyCallBacks || NULL == keyCallBacks->retain;
150	    Boolean keyReleaseNull = NULL == keyCallBacks || NULL == keyCallBacks->release;
151	    Boolean keyEquateNull = NULL == keyCallBacks || NULL == keyCallBacks->equal;
152	    Boolean keyHashNull = NULL == keyCallBacks || NULL == keyCallBacks->hash;
153	    Boolean keyDescribeNull = NULL == keyCallBacks || NULL == keyCallBacks->copyDescription;
154
155	    Boolean valueRetainNull = (useValueCB && (NULL == valueCallBacks || NULL == valueCallBacks->retain)) || (!useValueCB && keyRetainNull);
156	    Boolean valueReleaseNull = (useValueCB && (NULL == valueCallBacks || NULL == valueCallBacks->release)) || (!useValueCB && keyReleaseNull);
157	    Boolean valueEquateNull = (useValueCB && (NULL == valueCallBacks || NULL == valueCallBacks->equal)) || (!useValueCB && keyEquateNull);
158	    Boolean valueDescribeNull = (useValueCB && (NULL == valueCallBacks || NULL == valueCallBacks->copyDescription)) || (!useValueCB && keyDescribeNull);
159
160	    Boolean keyRetainStd = keyRetainNull || __CFTypeCollectionRetain == keyCallBacks->retain;
161	    Boolean keyReleaseStd = keyReleaseNull || __CFTypeCollectionRelease == keyCallBacks->release;
162	    Boolean keyEquateStd = keyEquateNull || CFEqual == keyCallBacks->equal;
163	    Boolean keyHashStd = keyHashNull || CFHash == keyCallBacks->hash;
164	    Boolean keyDescribeStd = keyDescribeNull || CFCopyDescription == keyCallBacks->copyDescription;
165
166	    Boolean valueRetainStd = (useValueCB && (valueRetainNull || __CFTypeCollectionRetain == valueCallBacks->retain)) || (!useValueCB && keyRetainStd);
167	    Boolean valueReleaseStd = (useValueCB && (valueReleaseNull || __CFTypeCollectionRelease == valueCallBacks->release)) || (!useValueCB && keyReleaseStd);
168	    Boolean valueEquateStd = (useValueCB && (valueEquateNull || CFEqual == valueCallBacks->equal)) || (!useValueCB && keyEquateStd);
169	    Boolean valueDescribeStd = (useValueCB && (valueDescribeNull || CFCopyDescription == valueCallBacks->copyDescription)) || (!useValueCB && keyDescribeStd);
170
171	    if (keyRetainStd && keyReleaseStd && keyEquateStd && keyHashStd && keyDescribeStd && valueRetainStd && valueReleaseStd && valueEquateStd && valueDescribeStd) {
172		set_cb = true;
173		if (!(keyRetainNull || keyReleaseNull || keyEquateNull || keyHashNull || keyDescribeNull || valueRetainNull || valueReleaseNull || valueEquateNull || valueDescribeNull)) {
174		    std_cb = true;
175		} else {
176		    // just set these to tickle the GC Strong logic below in a way that mimics past practice
177		    key_retain = keyCallBacks ? keyCallBacks->retain : NULL;
178		    key_release = keyCallBacks ? keyCallBacks->release : NULL;
179		    if (useValueCB) {
180			value_retain = valueCallBacks ? valueCallBacks->retain : NULL;
181			value_release = valueCallBacks ? valueCallBacks->release : NULL;
182		    } else {
183			value_retain = key_retain;
184			value_release = key_release;
185		    }
186		}
187	    }
188	}
189
190        if (!set_cb) {
191            key_retain = keyCallBacks ? keyCallBacks->retain : NULL;
192            key_release = keyCallBacks ? keyCallBacks->release : NULL;
193            if (useValueCB) {
194                value_retain = valueCallBacks ? valueCallBacks->retain : NULL;
195                value_release = valueCallBacks ? valueCallBacks->release : NULL;
196            } else {
197                value_retain = key_retain;
198                value_release = key_release;
199            }
200        }
201
202        if (std_cb || value_retain != NULL || value_release != NULL) {
203            flags |= kCFBasicHashStrongValues;
204        }
205        if (std_cb || key_retain != NULL || key_release != NULL) {
206            flags |= kCFBasicHashStrongKeys;
207        }
208    }
209
210
211    CFBasicHashCallbacks callbacks;
212    callbacks.retainKey = keyCallBacks ? (uintptr_t (*)(CFAllocatorRef, uintptr_t))keyCallBacks->retain : NULL;
213    callbacks.releaseKey = keyCallBacks ? (void (*)(CFAllocatorRef, uintptr_t))keyCallBacks->release : NULL;
214    callbacks.equateKeys = keyCallBacks ? (Boolean (*)(uintptr_t, uintptr_t))keyCallBacks->equal : NULL;
215    callbacks.hashKey = keyCallBacks ? (CFHashCode (*)(uintptr_t))keyCallBacks->hash : NULL;
216    callbacks.getIndirectKey = NULL;
217    callbacks.copyKeyDescription = keyCallBacks ? (CFStringRef (*)(uintptr_t))keyCallBacks->copyDescription : NULL;
218    callbacks.retainValue = useValueCB ? (valueCallBacks ? (uintptr_t (*)(CFAllocatorRef, uintptr_t))valueCallBacks->retain : NULL) : (callbacks.retainKey);
219    callbacks.releaseValue = useValueCB ? (valueCallBacks ? (void (*)(CFAllocatorRef, uintptr_t))valueCallBacks->release : NULL) : (callbacks.releaseKey);
220    callbacks.equateValues = useValueCB ? (valueCallBacks ? (Boolean (*)(uintptr_t, uintptr_t))valueCallBacks->equal : NULL) : (callbacks.equateKeys);
221    callbacks.copyValueDescription = useValueCB ? (valueCallBacks ? (CFStringRef (*)(uintptr_t))valueCallBacks->copyDescription : NULL) : (callbacks.copyKeyDescription);
222
223    CFBasicHashRef ht = CFBasicHashCreate(allocator, flags, &callbacks);
224    return ht;
225}
226
227#if CFDictionary
228CF_PRIVATE CFHashRef __CFBagCreateTransfer(CFAllocatorRef allocator, const_any_pointer_t *klist, const_any_pointer_t *vlist, CFIndex numValues) {
229#endif
230#if CFSet || CFBag
231CF_PRIVATE CFHashRef __CFBagCreateTransfer(CFAllocatorRef allocator, const_any_pointer_t *klist, CFIndex numValues) {
232    const_any_pointer_t *vlist = klist;
233#endif
234    CFTypeID typeID = CFBagGetTypeID();
235    CFAssert2(0 <= numValues, __kCFLogAssertion, "%s(): numValues (%ld) cannot be less than zero", __PRETTY_FUNCTION__, numValues);
236    CFOptionFlags flags = kCFBasicHashLinearHashing; // kCFBasicHashExponentialHashing
237    flags |= (CFDictionary ? kCFBasicHashHasKeys : 0) | (CFBag ? kCFBasicHashHasCounts : 0);
238
239    CFBasicHashCallbacks callbacks;
240    callbacks.retainKey = (uintptr_t (*)(CFAllocatorRef, uintptr_t))kCFTypeBagKeyCallBacks.retain;
241    callbacks.releaseKey = (void (*)(CFAllocatorRef, uintptr_t))kCFTypeBagKeyCallBacks.release;
242    callbacks.equateKeys = (Boolean (*)(uintptr_t, uintptr_t))kCFTypeBagKeyCallBacks.equal;
243    callbacks.hashKey = (CFHashCode (*)(uintptr_t))kCFTypeBagKeyCallBacks.hash;
244    callbacks.getIndirectKey = NULL;
245    callbacks.copyKeyDescription = (CFStringRef (*)(uintptr_t))kCFTypeBagKeyCallBacks.copyDescription;
246    callbacks.retainValue = CFDictionary ? (uintptr_t (*)(CFAllocatorRef, uintptr_t))kCFTypeBagValueCallBacks.retain : callbacks.retainKey;
247    callbacks.releaseValue = CFDictionary ? (void (*)(CFAllocatorRef, uintptr_t))kCFTypeBagValueCallBacks.release : callbacks.releaseKey;
248    callbacks.equateValues = CFDictionary ? (Boolean (*)(uintptr_t, uintptr_t))kCFTypeBagValueCallBacks.equal : callbacks.equateKeys;
249    callbacks.copyValueDescription = CFDictionary ? (CFStringRef (*)(uintptr_t))kCFTypeBagValueCallBacks.copyDescription : callbacks.copyKeyDescription;
250
251    CFBasicHashRef ht = CFBasicHashCreate(allocator, flags, &callbacks);
252    CFBasicHashSuppressRC(ht);
253    if (0 < numValues) CFBasicHashSetCapacity(ht, numValues);
254    for (CFIndex idx = 0; idx < numValues; idx++) {
255        CFBasicHashAddValue(ht, (uintptr_t)klist[idx], (uintptr_t)vlist[idx]);
256    }
257    CFBasicHashUnsuppressRC(ht);
258    CFBasicHashMakeImmutable(ht);
259    _CFRuntimeSetInstanceTypeIDAndIsa(ht, typeID);
260    if (__CFOASafe) __CFSetLastAllocationEventName(ht, "CFBag (immutable)");
261    return (CFHashRef)ht;
262}
263
264#if CFDictionary
265CFHashRef CFBagCreate(CFAllocatorRef allocator, const_any_pointer_t *klist, const_any_pointer_t *vlist, CFIndex numValues, const CFBagKeyCallBacks *keyCallBacks, const CFBagValueCallBacks *valueCallBacks) {
266#endif
267#if CFSet || CFBag
268CFHashRef CFBagCreate(CFAllocatorRef allocator, const_any_pointer_t *klist, CFIndex numValues, const CFBagKeyCallBacks *keyCallBacks) {
269    const_any_pointer_t *vlist = klist;
270    const CFBagValueCallBacks *valueCallBacks = 0;
271#endif
272    CFTypeID typeID = CFBagGetTypeID();
273    CFAssert2(0 <= numValues, __kCFLogAssertion, "%s(): numValues (%ld) cannot be less than zero", __PRETTY_FUNCTION__, numValues);
274    CFBasicHashRef ht = __CFBagCreateGeneric(allocator, keyCallBacks, valueCallBacks, CFDictionary);
275    if (!ht) return NULL;
276    if (0 < numValues) CFBasicHashSetCapacity(ht, numValues);
277    for (CFIndex idx = 0; idx < numValues; idx++) {
278        CFBasicHashAddValue(ht, (uintptr_t)klist[idx], (uintptr_t)vlist[idx]);
279    }
280    CFBasicHashMakeImmutable(ht);
281    _CFRuntimeSetInstanceTypeIDAndIsa(ht, typeID);
282    if (__CFOASafe) __CFSetLastAllocationEventName(ht, "CFBag (immutable)");
283    return (CFHashRef)ht;
284}
285
286#if CFDictionary
287CFMutableHashRef CFBagCreateMutable(CFAllocatorRef allocator, CFIndex capacity, const CFBagKeyCallBacks *keyCallBacks, const CFBagValueCallBacks *valueCallBacks) {
288#endif
289#if CFSet || CFBag
290CFMutableHashRef CFBagCreateMutable(CFAllocatorRef allocator, CFIndex capacity, const CFBagKeyCallBacks *keyCallBacks) {
291    const CFBagValueCallBacks *valueCallBacks = 0;
292#endif
293    CFTypeID typeID = CFBagGetTypeID();
294    CFAssert2(0 <= capacity, __kCFLogAssertion, "%s(): capacity (%ld) cannot be less than zero", __PRETTY_FUNCTION__, capacity);
295    CFBasicHashRef ht = __CFBagCreateGeneric(allocator, keyCallBacks, valueCallBacks, CFDictionary);
296    if (!ht) return NULL;
297    _CFRuntimeSetInstanceTypeIDAndIsa(ht, typeID);
298    if (__CFOASafe) __CFSetLastAllocationEventName(ht, "CFBag (mutable)");
299    return (CFMutableHashRef)ht;
300}
301
302CFHashRef CFBagCreateCopy(CFAllocatorRef allocator, CFHashRef other) {
303    CFTypeID typeID = CFBagGetTypeID();
304    CFAssert1(other, __kCFLogAssertion, "%s(): other CFBag cannot be NULL", __PRETTY_FUNCTION__);
305    __CFGenericValidateType(other, typeID);
306    CFBasicHashRef ht = NULL;
307    if (CF_IS_OBJC(typeID, other)) {
308        CFIndex numValues = CFBagGetCount(other);
309        const_any_pointer_t vbuffer[256], kbuffer[256];
310        const_any_pointer_t *vlist = (numValues <= 256) ? vbuffer : (const_any_pointer_t *)CFAllocatorAllocate(kCFAllocatorSystemDefault, numValues * sizeof(const_any_pointer_t), 0);
311#if CFSet || CFBag
312        const_any_pointer_t *klist = vlist;
313        CFBagGetValues(other, vlist);
314#endif
315#if CFDictionary
316        const_any_pointer_t *klist = (numValues <= 256) ? kbuffer : (const_any_pointer_t *)CFAllocatorAllocate(kCFAllocatorSystemDefault, numValues * sizeof(const_any_pointer_t), 0);
317        CFDictionaryGetKeysAndValues(other, klist, vlist);
318#endif
319        ht = __CFBagCreateGeneric(allocator, & kCFTypeBagKeyCallBacks, CFDictionary ? & kCFTypeBagValueCallBacks : NULL, CFDictionary);
320        if (ht && 0 < numValues) CFBasicHashSetCapacity(ht, numValues);
321        for (CFIndex idx = 0; ht && idx < numValues; idx++) {
322            CFBasicHashAddValue(ht, (uintptr_t)klist[idx], (uintptr_t)vlist[idx]);
323        }
324        if (klist != kbuffer && klist != vlist) CFAllocatorDeallocate(kCFAllocatorSystemDefault, klist);
325        if (vlist != vbuffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, vlist);
326    } else {
327        ht = CFBasicHashCreateCopy(allocator, (CFBasicHashRef)other);
328    }
329    if (!ht) return NULL;
330    CFBasicHashMakeImmutable(ht);
331    _CFRuntimeSetInstanceTypeIDAndIsa(ht, typeID);
332    if (__CFOASafe) __CFSetLastAllocationEventName(ht, "CFBag (immutable)");
333    return (CFHashRef)ht;
334}
335
336CFMutableHashRef CFBagCreateMutableCopy(CFAllocatorRef allocator, CFIndex capacity, CFHashRef other) {
337    CFTypeID typeID = CFBagGetTypeID();
338    CFAssert1(other, __kCFLogAssertion, "%s(): other CFBag cannot be NULL", __PRETTY_FUNCTION__);
339    __CFGenericValidateType(other, typeID);
340    CFAssert2(0 <= capacity, __kCFLogAssertion, "%s(): capacity (%ld) cannot be less than zero", __PRETTY_FUNCTION__, capacity);
341    CFBasicHashRef ht = NULL;
342    if (CF_IS_OBJC(typeID, other)) {
343        CFIndex numValues = CFBagGetCount(other);
344        const_any_pointer_t vbuffer[256], kbuffer[256];
345        const_any_pointer_t *vlist = (numValues <= 256) ? vbuffer : (const_any_pointer_t *)CFAllocatorAllocate(kCFAllocatorSystemDefault, numValues * sizeof(const_any_pointer_t), 0);
346#if CFSet || CFBag
347        const_any_pointer_t *klist = vlist;
348        CFBagGetValues(other, vlist);
349#endif
350#if CFDictionary
351        const_any_pointer_t *klist = (numValues <= 256) ? kbuffer : (const_any_pointer_t *)CFAllocatorAllocate(kCFAllocatorSystemDefault, numValues * sizeof(const_any_pointer_t), 0);
352        CFDictionaryGetKeysAndValues(other, klist, vlist);
353#endif
354        ht = __CFBagCreateGeneric(allocator, & kCFTypeBagKeyCallBacks, CFDictionary ? & kCFTypeBagValueCallBacks : NULL, CFDictionary);
355        if (ht && 0 < numValues) CFBasicHashSetCapacity(ht, numValues);
356        for (CFIndex idx = 0; ht && idx < numValues; idx++) {
357            CFBasicHashAddValue(ht, (uintptr_t)klist[idx], (uintptr_t)vlist[idx]);
358        }
359        if (klist != kbuffer && klist != vlist) CFAllocatorDeallocate(kCFAllocatorSystemDefault, klist);
360        if (vlist != vbuffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, vlist);
361    } else {
362        ht = CFBasicHashCreateCopy(allocator, (CFBasicHashRef)other);
363    }
364    if (!ht) return NULL;
365    _CFRuntimeSetInstanceTypeIDAndIsa(ht, typeID);
366    if (__CFOASafe) __CFSetLastAllocationEventName(ht, "CFBag (mutable)");
367    return (CFMutableHashRef)ht;
368}
369
370CFIndex CFBagGetCount(CFHashRef hc) {
371    if (CFDictionary) CF_OBJC_FUNCDISPATCHV(__kCFBagTypeID, CFIndex, (NSDictionary *)hc, count);
372    if (CFSet) CF_OBJC_FUNCDISPATCHV(__kCFBagTypeID, CFIndex, (NSSet *)hc, count);
373    __CFGenericValidateType(hc, __kCFBagTypeID);
374    return CFBasicHashGetCount((CFBasicHashRef)hc);
375}
376
377#if CFDictionary
378CFIndex CFBagGetCountOfKey(CFHashRef hc, const_any_pointer_t key) {
379#endif
380#if CFSet || CFBag
381CFIndex CFBagGetCountOfValue(CFHashRef hc, const_any_pointer_t key) {
382#endif
383    if (CFDictionary) CF_OBJC_FUNCDISPATCHV(__kCFBagTypeID, CFIndex, (NSDictionary *)hc, countForKey:(id)key);
384    if (CFSet) CF_OBJC_FUNCDISPATCHV(__kCFBagTypeID, CFIndex, (NSSet *)hc, countForObject:(id)key);
385    __CFGenericValidateType(hc, __kCFBagTypeID);
386    return CFBasicHashGetCountOfKey((CFBasicHashRef)hc, (uintptr_t)key);
387}
388
389#if CFDictionary
390Boolean CFBagContainsKey(CFHashRef hc, const_any_pointer_t key) {
391#endif
392#if CFSet || CFBag
393Boolean CFBagContainsValue(CFHashRef hc, const_any_pointer_t key) {
394#endif
395    if (CFDictionary) CF_OBJC_FUNCDISPATCHV(__kCFBagTypeID, char, (NSDictionary *)hc, containsKey:(id)key);
396    if (CFSet) CF_OBJC_FUNCDISPATCHV(__kCFBagTypeID, char, (NSSet *)hc, containsObject:(id)key);
397    __CFGenericValidateType(hc, __kCFBagTypeID);
398    return (0 < CFBasicHashGetCountOfKey((CFBasicHashRef)hc, (uintptr_t)key));
399}
400
401const_any_pointer_t CFBagGetValue(CFHashRef hc, const_any_pointer_t key) {
402    if (CFDictionary) CF_OBJC_FUNCDISPATCHV(__kCFBagTypeID, const_any_pointer_t, (NSDictionary *)hc, objectForKey:(id)key);
403    if (CFSet) CF_OBJC_FUNCDISPATCHV(__kCFBagTypeID, const_any_pointer_t, (NSSet *)hc, member:(id)key);
404    __CFGenericValidateType(hc, __kCFBagTypeID);
405    CFBasicHashBucket bkt = CFBasicHashFindBucket((CFBasicHashRef)hc, (uintptr_t)key);
406    return (0 < bkt.count ? (const_any_pointer_t)bkt.weak_value : 0);
407}
408
409Boolean CFBagGetValueIfPresent(CFHashRef hc, const_any_pointer_t key, const_any_pointer_t *value) {
410    if (CFDictionary) CF_OBJC_FUNCDISPATCHV(__kCFBagTypeID, Boolean, (NSDictionary *)hc, __getValue:(id *)value forKey:(id)key);
411    if (CFSet) CF_OBJC_FUNCDISPATCHV(__kCFBagTypeID, Boolean, (NSSet *)hc, __getValue:(id *)value forObj:(id)key);
412    __CFGenericValidateType(hc, __kCFBagTypeID);
413    CFBasicHashBucket bkt = CFBasicHashFindBucket((CFBasicHashRef)hc, (uintptr_t)key);
414    if (0 < bkt.count) {
415        if (value) {
416            if (kCFUseCollectableAllocator && (CFBasicHashGetFlags((CFBasicHashRef)hc) & kCFBasicHashStrongValues)) {
417                __CFAssignWithWriteBarrier((void **)value, (void *)bkt.weak_value);
418            } else {
419                *value = (const_any_pointer_t)bkt.weak_value;
420            }
421        }
422        return true;
423    }
424    return false;
425}
426
427#if CFDictionary
428CFIndex CFDictionaryGetCountOfValue(CFHashRef hc, const_any_pointer_t value) {
429    CF_OBJC_FUNCDISPATCHV(__kCFBagTypeID, CFIndex, (NSDictionary *)hc, countForObject:(id)value);
430    __CFGenericValidateType(hc, __kCFBagTypeID);
431    return CFBasicHashGetCountOfValue((CFBasicHashRef)hc, (uintptr_t)value);
432}
433
434Boolean CFDictionaryContainsValue(CFHashRef hc, const_any_pointer_t value) {
435    CF_OBJC_FUNCDISPATCHV(__kCFBagTypeID, char, (NSDictionary *)hc, containsObject:(id)value);
436    __CFGenericValidateType(hc, __kCFBagTypeID);
437    return (0 < CFBasicHashGetCountOfValue((CFBasicHashRef)hc, (uintptr_t)value));
438}
439
440CF_EXPORT Boolean CFDictionaryGetKeyIfPresent(CFHashRef hc, const_any_pointer_t key, const_any_pointer_t *actualkey) {
441    __CFGenericValidateType(hc, __kCFBagTypeID);
442    CFBasicHashBucket bkt = CFBasicHashFindBucket((CFBasicHashRef)hc, (uintptr_t)key);
443    if (0 < bkt.count) {
444        if (actualkey) {
445            if (kCFUseCollectableAllocator && (CFBasicHashGetFlags((CFBasicHashRef)hc) & kCFBasicHashStrongKeys)) {
446                __CFAssignWithWriteBarrier((void **)actualkey, (void *)bkt.weak_key);
447            } else {
448                *actualkey = (const_any_pointer_t)bkt.weak_key;
449            }
450        }
451        return true;
452    }
453    return false;
454}
455#endif
456
457#if CFDictionary
458void CFBagGetKeysAndValues(CFHashRef hc, const_any_pointer_t *keybuf, const_any_pointer_t *valuebuf) {
459#endif
460#if CFSet || CFBag
461void CFBagGetValues(CFHashRef hc, const_any_pointer_t *keybuf) {
462    const_any_pointer_t *valuebuf = 0;
463#endif
464    if (CFDictionary) CF_OBJC_FUNCDISPATCHV(__kCFBagTypeID, void, (NSDictionary *)hc, getObjects:(id *)valuebuf andKeys:(id *)keybuf);
465    if (CFSet) CF_OBJC_FUNCDISPATCHV(__kCFBagTypeID, void, (NSSet *)hc, getObjects:(id *)keybuf);
466    __CFGenericValidateType(hc, __kCFBagTypeID);
467    if (kCFUseCollectableAllocator) {
468        CFOptionFlags flags = CFBasicHashGetFlags((CFBasicHashRef)hc);
469        __block const_any_pointer_t *keys = keybuf;
470        __block const_any_pointer_t *values = valuebuf;
471        CFBasicHashApply((CFBasicHashRef)hc, ^(CFBasicHashBucket bkt) {
472                for (CFIndex cnt = bkt.count; cnt--;) {
473                    if (keybuf && (flags & kCFBasicHashStrongKeys)) { __CFAssignWithWriteBarrier((void **)keys, (void *)bkt.weak_key); keys++; }
474                    if (keybuf && !(flags & kCFBasicHashStrongKeys)) { *keys++ = (const_any_pointer_t)bkt.weak_key; }
475                    if (valuebuf && (flags & kCFBasicHashStrongValues)) { __CFAssignWithWriteBarrier((void **)values, (void *)bkt.weak_value); values++; }
476                    if (valuebuf && !(flags & kCFBasicHashStrongValues)) { *values++ = (const_any_pointer_t)bkt.weak_value; }
477                }
478                return (Boolean)true;
479            });
480    } else {
481        CFBasicHashGetElements((CFBasicHashRef)hc, CFBagGetCount(hc), (uintptr_t *)valuebuf, (uintptr_t *)keybuf);
482    }
483}
484
485void CFBagApplyFunction(CFHashRef hc, CFBagApplierFunction applier, any_pointer_t context) {
486    FAULT_CALLBACK((void **)&(applier));
487    if (CFDictionary) CF_OBJC_FUNCDISPATCHV(__kCFBagTypeID, void, (NSDictionary *)hc, __apply:(void (*)(const void *, const void *, void *))applier context:(void *)context);
488    if (CFSet) CF_OBJC_FUNCDISPATCHV(__kCFBagTypeID, void, (NSSet *)hc, __applyValues:(void (*)(const void *, void *))applier context:(void *)context);
489    __CFGenericValidateType(hc, __kCFBagTypeID);
490    CFBasicHashApply((CFBasicHashRef)hc, ^(CFBasicHashBucket bkt) {
491#if CFDictionary
492            INVOKE_CALLBACK3(applier, (const_any_pointer_t)bkt.weak_key, (const_any_pointer_t)bkt.weak_value, context);
493#endif
494#if CFSet
495            INVOKE_CALLBACK2(applier, (const_any_pointer_t)bkt.weak_value, context);
496#endif
497#if CFBag
498            for (CFIndex cnt = bkt.count; cnt--;) {
499                INVOKE_CALLBACK2(applier, (const_any_pointer_t)bkt.weak_value, context);
500            }
501#endif
502            return (Boolean)true;
503        });
504}
505
506// This function is for Foundation's benefit; no one else should use it.
507CF_EXPORT unsigned long _CFBagFastEnumeration(CFHashRef hc, struct __objcFastEnumerationStateEquivalent *state, void *stackbuffer, unsigned long count) {
508    if (CF_IS_OBJC(__kCFBagTypeID, hc)) return 0;
509    __CFGenericValidateType(hc, __kCFBagTypeID);
510    return __CFBasicHashFastEnumeration((CFBasicHashRef)hc, (struct __objcFastEnumerationStateEquivalent2 *)state, stackbuffer, count);
511}
512
513// This function is for Foundation's benefit; no one else should use it.
514CF_EXPORT Boolean _CFBagIsMutable(CFHashRef hc) {
515    if (CF_IS_OBJC(__kCFBagTypeID, hc)) return false;
516    __CFGenericValidateType(hc, __kCFBagTypeID);
517    return CFBasicHashIsMutable((CFBasicHashRef)hc);
518}
519
520// This function is for Foundation's benefit; no one else should use it.
521CF_EXPORT void _CFBagSetCapacity(CFMutableHashRef hc, CFIndex cap) {
522    if (CF_IS_OBJC(__kCFBagTypeID, hc)) return;
523    __CFGenericValidateType(hc, __kCFBagTypeID);
524    CFAssert2(CFBasicHashIsMutable((CFBasicHashRef)hc), __kCFLogAssertion, "%s(): immutable collection %p passed to mutating operation", __PRETTY_FUNCTION__, hc);
525    CFAssert3(CFBagGetCount(hc) <= cap, __kCFLogAssertion, "%s(): desired capacity (%ld) is less than count (%ld)", __PRETTY_FUNCTION__, cap, CFBagGetCount(hc));
526    CFBasicHashSetCapacity((CFBasicHashRef)hc, cap);
527}
528
529CF_INLINE CFIndex __CFBagGetKVOBit(CFHashRef hc) {
530    return __CFBitfieldGetValue(((CFRuntimeBase *)hc)->_cfinfo[CF_INFO_BITS], 0, 0);
531}
532
533CF_INLINE void __CFBagSetKVOBit(CFHashRef hc, CFIndex bit) {
534    __CFBitfieldSetValue(((CFRuntimeBase *)hc)->_cfinfo[CF_INFO_BITS], 0, 0, ((uintptr_t)bit & 0x1));
535}
536
537// This function is for Foundation's benefit; no one else should use it.
538CF_EXPORT CFIndex _CFBagGetKVOBit(CFHashRef hc) {
539    return __CFBagGetKVOBit(hc);
540}
541
542// This function is for Foundation's benefit; no one else should use it.
543CF_EXPORT void _CFBagSetKVOBit(CFHashRef hc, CFIndex bit) {
544    __CFBagSetKVOBit(hc, bit);
545}
546
547
548#if !defined(CF_OBJC_KVO_WILLCHANGE)
549#define CF_OBJC_KVO_WILLCHANGE(obj, key)
550#define CF_OBJC_KVO_DIDCHANGE(obj, key)
551#define CF_OBJC_KVO_WILLCHANGEALL(obj)
552#define CF_OBJC_KVO_DIDCHANGEALL(obj)
553#endif
554
555#if CFDictionary
556void CFBagAddValue(CFMutableHashRef hc, const_any_pointer_t key, const_any_pointer_t value) {
557#endif
558#if CFSet || CFBag
559void CFBagAddValue(CFMutableHashRef hc, const_any_pointer_t key) {
560    const_any_pointer_t value = key;
561#endif
562    if (CFDictionary) CF_OBJC_FUNCDISPATCHV(__kCFBagTypeID, void, (NSMutableDictionary *)hc, __addObject:(id)value forKey:(id)key);
563    if (CFSet) CF_OBJC_FUNCDISPATCHV(__kCFBagTypeID, void, (NSMutableSet *)hc, addObject:(id)key);
564    __CFGenericValidateType(hc, __kCFBagTypeID);
565    CFAssert2(CFBasicHashIsMutable((CFBasicHashRef)hc), __kCFLogAssertion, "%s(): immutable collection %p passed to mutating operation", __PRETTY_FUNCTION__, hc);
566    if (!CFBasicHashIsMutable((CFBasicHashRef)hc)) {
567        CFLog(3, CFSTR("%s(): immutable collection %p given to mutating function"), __PRETTY_FUNCTION__, hc);
568    }
569    CF_OBJC_KVO_WILLCHANGE(hc, key);
570    CFBasicHashAddValue((CFBasicHashRef)hc, (uintptr_t)key, (uintptr_t)value);
571    CF_OBJC_KVO_DIDCHANGE(hc, key);
572}
573
574#if CFDictionary
575void CFBagReplaceValue(CFMutableHashRef hc, const_any_pointer_t key, const_any_pointer_t value) {
576#endif
577#if CFSet || CFBag
578void CFBagReplaceValue(CFMutableHashRef hc, const_any_pointer_t key) {
579    const_any_pointer_t value = key;
580#endif
581    if (CFDictionary) CF_OBJC_FUNCDISPATCHV(__kCFBagTypeID, void, (NSMutableDictionary *)hc, replaceObject:(id)value forKey:(id)key);
582    if (CFSet) CF_OBJC_FUNCDISPATCHV(__kCFBagTypeID, void, (NSMutableSet *)hc, replaceObject:(id)key);
583    __CFGenericValidateType(hc, __kCFBagTypeID);
584    CFAssert2(CFBasicHashIsMutable((CFBasicHashRef)hc), __kCFLogAssertion, "%s(): immutable collection %p passed to mutating operation", __PRETTY_FUNCTION__, hc);
585    if (!CFBasicHashIsMutable((CFBasicHashRef)hc)) {
586        CFLog(3, CFSTR("%s(): immutable collection %p given to mutating function"), __PRETTY_FUNCTION__, hc);
587    }
588    CF_OBJC_KVO_WILLCHANGE(hc, key);
589    CFBasicHashReplaceValue((CFBasicHashRef)hc, (uintptr_t)key, (uintptr_t)value);
590    CF_OBJC_KVO_DIDCHANGE(hc, key);
591}
592
593#if CFDictionary
594void CFBagSetValue(CFMutableHashRef hc, const_any_pointer_t key, const_any_pointer_t value) {
595#endif
596#if CFSet || CFBag
597void CFBagSetValue(CFMutableHashRef hc, const_any_pointer_t key) {
598    const_any_pointer_t value = key;
599#endif
600    if (CFDictionary) CF_OBJC_FUNCDISPATCHV(__kCFBagTypeID, void, (NSMutableDictionary *)hc, __setObject:(id)value forKey:(id)key);
601    if (CFSet) CF_OBJC_FUNCDISPATCHV(__kCFBagTypeID, void, (NSMutableSet *)hc, setObject:(id)key);
602    __CFGenericValidateType(hc, __kCFBagTypeID);
603    CFAssert2(CFBasicHashIsMutable((CFBasicHashRef)hc), __kCFLogAssertion, "%s(): immutable collection %p passed to mutating operation", __PRETTY_FUNCTION__, hc);
604    if (!CFBasicHashIsMutable((CFBasicHashRef)hc)) {
605        CFLog(3, CFSTR("%s(): immutable collection %p given to mutating function"), __PRETTY_FUNCTION__, hc);
606    }
607    CF_OBJC_KVO_WILLCHANGE(hc, key);
608//#warning this for a dictionary used to not replace the key
609    CFBasicHashSetValue((CFBasicHashRef)hc, (uintptr_t)key, (uintptr_t)value);
610    CF_OBJC_KVO_DIDCHANGE(hc, key);
611}
612
613void CFBagRemoveValue(CFMutableHashRef hc, const_any_pointer_t key) {
614    if (CFDictionary) CF_OBJC_FUNCDISPATCHV(__kCFBagTypeID, void, (NSMutableDictionary *)hc, removeObjectForKey:(id)key);
615    if (CFSet) CF_OBJC_FUNCDISPATCHV(__kCFBagTypeID, void, (NSMutableSet *)hc, removeObject:(id)key);
616    __CFGenericValidateType(hc, __kCFBagTypeID);
617    CFAssert2(CFBasicHashIsMutable((CFBasicHashRef)hc), __kCFLogAssertion, "%s(): immutable collection %p passed to mutating operation", __PRETTY_FUNCTION__, hc);
618    if (!CFBasicHashIsMutable((CFBasicHashRef)hc)) {
619        CFLog(3, CFSTR("%s(): immutable collection %p given to mutating function"), __PRETTY_FUNCTION__, hc);
620    }
621    CF_OBJC_KVO_WILLCHANGE(hc, key);
622    CFBasicHashRemoveValue((CFBasicHashRef)hc, (uintptr_t)key);
623    CF_OBJC_KVO_DIDCHANGE(hc, key);
624}
625
626void CFBagRemoveAllValues(CFMutableHashRef hc) {
627    if (CFDictionary) CF_OBJC_FUNCDISPATCHV(__kCFBagTypeID, void, (NSMutableDictionary *)hc, removeAllObjects);
628    if (CFSet) CF_OBJC_FUNCDISPATCHV(__kCFBagTypeID, void, (NSMutableSet *)hc, removeAllObjects);
629    __CFGenericValidateType(hc, __kCFBagTypeID);
630    CFAssert2(CFBasicHashIsMutable((CFBasicHashRef)hc), __kCFLogAssertion, "%s(): immutable collection %p passed to mutating operation", __PRETTY_FUNCTION__, hc);
631    if (!CFBasicHashIsMutable((CFBasicHashRef)hc)) {
632        CFLog(3, CFSTR("%s(): immutable collection %p given to mutating function"), __PRETTY_FUNCTION__, hc);
633    }
634    CF_OBJC_KVO_WILLCHANGEALL(hc);
635    CFBasicHashRemoveAllValues((CFBasicHashRef)hc);
636    CF_OBJC_KVO_DIDCHANGEALL(hc);
637}
638
639#undef CF_OBJC_KVO_WILLCHANGE
640#undef CF_OBJC_KVO_DIDCHANGE
641#undef CF_OBJC_KVO_WILLCHANGEALL
642#undef CF_OBJC_KVO_DIDCHANGEALL
643
644