X-Git-Url: https://git.saurik.com/apple/cf.git/blobdiff_plain/b0e0750aaee7a1a2cd8e3aa918bd9fc756e9dfcf..cf7d2af96685aba74e84652f9ed1098e9253902e:/CFSet.c?ds=inline diff --git a/CFSet.c b/CFSet.c index 4c0e1f0..6c84711 100644 --- a/CFSet.c +++ b/CFSet.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008 Apple Inc. All rights reserved. + * Copyright (c) 2009 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,17 +21,19 @@ * @APPLE_LICENSE_HEADER_END@ */ /* CFSet.c - Copyright 1998-2006, Apple, Inc. All rights reserved. + Copyright 1998-2008, Apple, Inc. All rights reserved. Responsibility: Christopher Kane - Machine generated from Notes/HashingCode.template + Machine generated from Notes/HashingCode.template */ + #include #include "CFInternal.h" -#include +#include "CFBasicHash.h" +#include #define CFDictionary 0 #define CFSet 0 @@ -48,7 +50,8 @@ static const CFSetValueCallBacks __kCFNullSetValueCallBacks = {0, NULL, NULL, NU #define CFHashRef CFDictionaryRef #define CFMutableHashRef CFMutableDictionaryRef -#define __kCFHashTypeID __kCFDictionaryTypeID +#define CFHashKeyCallBacks CFSetKeyCallBacks +#define CFHashValueCallBacks CFSetValueCallBacks #endif #if CFSet @@ -65,7 +68,8 @@ static const CFSetCallBacks __kCFNullSetCallBacks = {0, NULL, NULL, NULL, NULL, #define CFHashRef CFSetRef #define CFMutableHashRef CFMutableSetRef -#define __kCFHashTypeID __kCFSetTypeID +#define CFHashKeyCallBacks CFSetCallBacks +#define CFHashValueCallBacks CFSetCallBacks #endif #if CFBag @@ -82,566 +86,29 @@ static const CFSetCallBacks __kCFNullSetCallBacks = {0, NULL, NULL, NULL, NULL, #define CFHashRef CFBagRef #define CFMutableHashRef CFMutableBagRef -#define __kCFHashTypeID __kCFBagTypeID -#endif - -#define GETNEWKEY(newKey, oldKey) \ - any_t (*kretain)(CFAllocatorRef, any_t, any_pointer_t) = \ - !hasBeenFinalized(hc) \ - ? (any_t (*)(CFAllocatorRef,any_t,any_pointer_t))__CFSetGetKeyCallBacks(hc)->retain \ - : (any_t (*)(CFAllocatorRef,any_t,any_pointer_t))0; \ - any_t newKey = kretain ? (any_t)INVOKE_CALLBACK3(kretain, allocator, (any_t)key, hc->_context) : (any_t)oldKey - -#define RELEASEKEY(oldKey) \ - void (*krelease)(CFAllocatorRef, any_t, any_pointer_t) = \ - !hasBeenFinalized(hc) \ - ? (void (*)(CFAllocatorRef,any_t,any_pointer_t))__CFSetGetKeyCallBacks(hc)->release \ - : (void (*)(CFAllocatorRef,any_t,any_pointer_t))0; \ - if (krelease) INVOKE_CALLBACK3(krelease, allocator, oldKey, hc->_context) - -#if CFDictionary -#define GETNEWVALUE(newValue) \ - any_t (*vretain)(CFAllocatorRef, any_t, any_pointer_t) = \ - !hasBeenFinalized(hc) \ - ? (any_t (*)(CFAllocatorRef,any_t,any_pointer_t))__CFSetGetValueCallBacks(hc)->retain \ - : (any_t (*)(CFAllocatorRef,any_t,any_pointer_t))0; \ - any_t newValue = vretain ? (any_t)INVOKE_CALLBACK3(vretain, allocator, (any_t)value, hc->_context) : (any_t)value - -#define RELEASEVALUE(oldValue) \ - void (*vrelease)(CFAllocatorRef, any_t, any_pointer_t) = \ - !hasBeenFinalized(hc) \ - ? (void (*)(CFAllocatorRef,any_t,any_pointer_t))__CFSetGetValueCallBacks(hc)->release \ - : (void (*)(CFAllocatorRef,any_t,any_pointer_t))0; \ - if (vrelease) INVOKE_CALLBACK3(vrelease, allocator, oldValue, hc->_context) - +#define CFHashKeyCallBacks CFSetCallBacks +#define CFHashValueCallBacks CFSetCallBacks #endif -static void __CFSetHandleOutOfMemory(CFTypeRef obj, CFIndex numBytes) { - CFStringRef msg = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("Attempt to allocate %ld bytes for NS/CFSet failed"), numBytes); - CFBadErrorCallBack cb = _CFGetOutOfMemoryErrorCallBack(); - if (NULL == cb || !cb(obj, CFSTR("NS/CFSet"), msg)) { - CFLog(kCFLogLevelCritical, CFSTR("%@"), msg); - HALT; - } - CFRelease(msg); -} - - -// Max load is 3/4 number of buckets -CF_INLINE CFIndex __CFHashRoundUpCapacity(CFIndex capacity) { - return 3 * ((CFIndex)1 << (flsl((capacity - 1) / 3))); -} - -// Returns next power of two higher than the capacity -// threshold for the given input capacity. -CF_INLINE CFIndex __CFHashNumBucketsForCapacity(CFIndex capacity) { - return 4 * ((CFIndex)1 << (flsl((capacity - 1) / 3))); -} - -enum { /* Bits 1-0 */ - __kCFHashImmutable = 0, /* unchangable and fixed capacity */ - __kCFHashMutable = 1, /* changeable and variable capacity */ -}; - -enum { /* Bits 5-4 (value), 3-2 (key) */ - __kCFHashHasNullCallBacks = 0, - __kCFHashHasCFTypeCallBacks = 1, - __kCFHashHasCustomCallBacks = 3 /* callbacks are at end of header */ -}; - -// Under GC, we fudge the key/value memory in two ways -// First, if we had null callbacks or null for both retain/release, we use unscanned memory and get -// standard 'dangling' references. -// This means that if people were doing addValue:[xxx new] and never removing, well, that doesn't work -// -// Second, if we notice standard retain/release implementations we use scanned memory, and fudge the -// standard callbacks to generally do nothing if the collection was allocated in GC memory. On special -// CF objects, however, like those used for precious resources like video-card buffers, we do indeed -// do CFRetain on input and CFRelease on output. The tricky case is GC finalization; we need to remember -// that we did the CFReleases so that subsequent collection operations, like removal, don't double CFRelease. -// (In fact we don't really use CFRetain/CFRelease but go directly to the collector) -// - -enum { - __kCFHashFinalized = (1 << 7), - __kCFHashWeakKeys = (1 << 8), - __kCFHashWeakValues = (1 << 9) -}; typedef uintptr_t any_t; typedef const void * const_any_pointer_t; typedef void * any_pointer_t; -struct __CFSet { - CFRuntimeBase _base; - CFIndex _count; /* number of values */ - CFIndex _bucketsNum; /* number of buckets */ - CFIndex _bucketsUsed; /* number of used buckets */ - CFIndex _bucketsCap; /* maximum number of used buckets */ - CFIndex _mutations; - CFIndex _deletes; - any_pointer_t _context; /* private */ - CFOptionFlags _xflags; - any_t _marker; - any_t *_keys; /* can be NULL if not allocated yet */ - any_t *_values; /* can be NULL if not allocated yet */ -}; - -/* Bits 1-0 of the _xflags are used for mutability variety */ -/* Bits 3-2 of the _xflags are used for key callback indicator bits */ -/* Bits 5-4 of the _xflags are used for value callback indicator bits */ -/* Bit 6 of the _xflags is special KVO actions bit */ -/* Bits 7,8,9 are GC use */ - -CF_INLINE bool hasBeenFinalized(CFTypeRef collection) { - return __CFBitfieldGetValue(((const struct __CFSet *)collection)->_xflags, 7, 7) != 0; -} - -CF_INLINE void markFinalized(CFTypeRef collection) { - __CFBitfieldSetValue(((struct __CFSet *)collection)->_xflags, 7, 7, 1); -} - - -CF_INLINE CFIndex __CFHashGetType(CFHashRef hc) { - return __CFBitfieldGetValue(hc->_xflags, 1, 0); -} - -CF_INLINE CFIndex __CFSetGetSizeOfType(CFIndex t) { - CFIndex size = sizeof(struct __CFSet); - if (__CFBitfieldGetValue(t, 3, 2) == __kCFHashHasCustomCallBacks) { - size += sizeof(CFSetKeyCallBacks); - } - if (__CFBitfieldGetValue(t, 5, 4) == __kCFHashHasCustomCallBacks) { - size += sizeof(CFSetValueCallBacks); - } - return size; -} - -CF_INLINE const CFSetKeyCallBacks *__CFSetGetKeyCallBacks(CFHashRef hc) { - CFSetKeyCallBacks *result = NULL; - switch (__CFBitfieldGetValue(hc->_xflags, 3, 2)) { - case __kCFHashHasNullCallBacks: - return &__kCFNullSetKeyCallBacks; - case __kCFHashHasCFTypeCallBacks: - return &kCFTypeSetKeyCallBacks; - case __kCFHashHasCustomCallBacks: - break; - } - result = (CFSetKeyCallBacks *)((uint8_t *)hc + sizeof(struct __CFSet)); - return result; -} - -CF_INLINE Boolean __CFSetKeyCallBacksMatchNull(const CFSetKeyCallBacks *c) { - return (NULL == c || - (c->retain == __kCFNullSetKeyCallBacks.retain && - c->release == __kCFNullSetKeyCallBacks.release && - c->copyDescription == __kCFNullSetKeyCallBacks.copyDescription && - c->equal == __kCFNullSetKeyCallBacks.equal && - c->hash == __kCFNullSetKeyCallBacks.hash)); -} - -CF_INLINE Boolean __CFSetKeyCallBacksMatchCFType(const CFSetKeyCallBacks *c) { - return (&kCFTypeSetKeyCallBacks == c || - (c->retain == kCFTypeSetKeyCallBacks.retain && - c->release == kCFTypeSetKeyCallBacks.release && - c->copyDescription == kCFTypeSetKeyCallBacks.copyDescription && - c->equal == kCFTypeSetKeyCallBacks.equal && - c->hash == kCFTypeSetKeyCallBacks.hash)); -} - -CF_INLINE const CFSetValueCallBacks *__CFSetGetValueCallBacks(CFHashRef hc) { - CFSetValueCallBacks *result = NULL; - switch (__CFBitfieldGetValue(hc->_xflags, 5, 4)) { - case __kCFHashHasNullCallBacks: - return &__kCFNullSetValueCallBacks; - case __kCFHashHasCFTypeCallBacks: - return &kCFTypeSetValueCallBacks; - case __kCFHashHasCustomCallBacks: - break; - } - if (__CFBitfieldGetValue(hc->_xflags, 3, 2) == __kCFHashHasCustomCallBacks) { - result = (CFSetValueCallBacks *)((uint8_t *)hc + sizeof(struct __CFSet) + sizeof(CFSetKeyCallBacks)); - } else { - result = (CFSetValueCallBacks *)((uint8_t *)hc + sizeof(struct __CFSet)); - } - return result; -} - -CF_INLINE Boolean __CFSetValueCallBacksMatchNull(const CFSetValueCallBacks *c) { - return (NULL == c || - (c->retain == __kCFNullSetValueCallBacks.retain && - c->release == __kCFNullSetValueCallBacks.release && - c->copyDescription == __kCFNullSetValueCallBacks.copyDescription && - c->equal == __kCFNullSetValueCallBacks.equal)); -} - -CF_INLINE Boolean __CFSetValueCallBacksMatchCFType(const CFSetValueCallBacks *c) { - return (&kCFTypeSetValueCallBacks == c || - (c->retain == kCFTypeSetValueCallBacks.retain && - c->release == kCFTypeSetValueCallBacks.release && - c->copyDescription == kCFTypeSetValueCallBacks.copyDescription && - c->equal == kCFTypeSetValueCallBacks.equal)); -} - -CFIndex _CFSetGetKVOBit(CFHashRef hc) { - return __CFBitfieldGetValue(hc->_xflags, 6, 6); -} - -void _CFSetSetKVOBit(CFHashRef hc, CFIndex bit) { - __CFBitfieldSetValue(((CFMutableHashRef)hc)->_xflags, 6, 6, ((uintptr_t)bit & 0x1)); -} - -CF_INLINE Boolean __CFSetShouldShrink(CFHashRef hc) { - return (__kCFHashMutable == __CFHashGetType(hc)) && - !(CF_USING_COLLECTABLE_MEMORY && auto_zone_is_finalized(__CFCollectableZone, hc)) && /* GC: don't shrink finalizing hcs! */ - (hc->_bucketsNum < 4 * hc->_deletes || (256 <= hc->_bucketsCap && hc-> _bucketsUsed < 3 * hc->_bucketsCap / 16)); -} - -CF_INLINE CFIndex __CFHashGetOccurrenceCount(CFHashRef hc, CFIndex idx) { -#if CFBag - return hc->_values[idx]; -#endif - return 1; -} - -CF_INLINE Boolean __CFHashKeyIsValue(CFHashRef hc, any_t key) { - return (hc->_marker != key && ~hc->_marker != key) ? true : false; -} - -CF_INLINE Boolean __CFHashKeyIsMagic(CFHashRef hc, any_t key) { - return (hc->_marker == key || ~hc->_marker == key) ? true : false; -} - - -#if !defined(CF_OBJC_KVO_WILLCHANGE) -#define CF_OBJC_KVO_WILLCHANGE(obj, key) -#define CF_OBJC_KVO_DIDCHANGE(obj, key) -#endif - -CF_INLINE uintptr_t __CFSetScrambleHash(uintptr_t k) { -#if 0 - return k; -#else -#if __LP64__ - uintptr_t a = 0x4368726973746F70ULL; - uintptr_t b = 0x686572204B616E65ULL; -#else - uintptr_t a = 0x4B616E65UL; - uintptr_t b = 0x4B616E65UL; -#endif - uintptr_t c = 1; - a += k; -#if __LP64__ - a -= b; a -= c; a ^= (c >> 43); - b -= c; b -= a; b ^= (a << 9); - c -= a; c -= b; c ^= (b >> 8); - a -= b; a -= c; a ^= (c >> 38); - b -= c; b -= a; b ^= (a << 23); - c -= a; c -= b; c ^= (b >> 5); - a -= b; a -= c; a ^= (c >> 35); - b -= c; b -= a; b ^= (a << 49); - c -= a; c -= b; c ^= (b >> 11); - a -= b; a -= c; a ^= (c >> 12); - b -= c; b -= a; b ^= (a << 18); - c -= a; c -= b; c ^= (b >> 22); -#else - a -= b; a -= c; a ^= (c >> 13); - b -= c; b -= a; b ^= (a << 8); - c -= a; c -= b; c ^= (b >> 13); - a -= b; a -= c; a ^= (c >> 12); - b -= c; b -= a; b ^= (a << 16); - c -= a; c -= b; c ^= (b >> 5); - a -= b; a -= c; a ^= (c >> 3); - b -= c; b -= a; b ^= (a << 10); - c -= a; c -= b; c ^= (b >> 15); -#endif - return c; -#endif -} - -static CFIndex __CFSetFindBuckets1a(CFHashRef hc, any_t key) { - CFHashCode keyHash = (CFHashCode)key; - keyHash = __CFSetScrambleHash(keyHash); - any_t *keys = hc->_keys; - any_t marker = hc->_marker; - CFIndex probe = keyHash & (hc->_bucketsNum - 1); - CFIndex probeskip = 1; // See RemoveValue() for notes before changing this value - CFIndex start = probe; - for (;;) { - any_t currKey = keys[probe]; - if (marker == currKey) { /* empty */ - return kCFNotFound; - } else if (~marker == currKey) { /* deleted */ - /* do nothing */ - } else if (currKey == key) { - return probe; - } - probe = probe + probeskip; - // This alternative to probe % buckets assumes that - // probeskip is always positive and less than the - // number of buckets. - if (hc->_bucketsNum <= probe) { - probe -= hc->_bucketsNum; - } - if (start == probe) { - return kCFNotFound; - } - } -} - -static CFIndex __CFSetFindBuckets1b(CFHashRef hc, any_t key) { - const CFSetKeyCallBacks *cb = __CFSetGetKeyCallBacks(hc); - CFHashCode keyHash = cb->hash ? (CFHashCode)INVOKE_CALLBACK2(((CFHashCode (*)(any_t, any_pointer_t))cb->hash), key, hc->_context) : (CFHashCode)key; - keyHash = __CFSetScrambleHash(keyHash); - any_t *keys = hc->_keys; - any_t marker = hc->_marker; - CFIndex probe = keyHash & (hc->_bucketsNum - 1); - CFIndex probeskip = 1; // See RemoveValue() for notes before changing this value - CFIndex start = probe; - for (;;) { - any_t currKey = keys[probe]; - if (marker == currKey) { /* empty */ - return kCFNotFound; - } else if (~marker == currKey) { /* deleted */ - /* do nothing */ - } else if (currKey == key || (cb->equal && INVOKE_CALLBACK3((Boolean (*)(any_t, any_t, any_pointer_t))cb->equal, currKey, key, hc->_context))) { - return probe; - } - probe = probe + probeskip; - // This alternative to probe % buckets assumes that - // probeskip is always positive and less than the - // number of buckets. - if (hc->_bucketsNum <= probe) { - probe -= hc->_bucketsNum; - } - if (start == probe) { - return kCFNotFound; - } - } -} - -CF_INLINE CFIndex __CFSetFindBuckets1(CFHashRef hc, any_t key) { - if (__kCFHashHasNullCallBacks == __CFBitfieldGetValue(hc->_xflags, 3, 2)) { - return __CFSetFindBuckets1a(hc, key); - } - return __CFSetFindBuckets1b(hc, key); -} - -static void __CFSetFindBuckets2(CFHashRef hc, any_t key, CFIndex *match, CFIndex *nomatch) { - const CFSetKeyCallBacks *cb = __CFSetGetKeyCallBacks(hc); - CFHashCode keyHash = cb->hash ? (CFHashCode)INVOKE_CALLBACK2(((CFHashCode (*)(any_t, any_pointer_t))cb->hash), key, hc->_context) : (CFHashCode)key; - keyHash = __CFSetScrambleHash(keyHash); - any_t *keys = hc->_keys; - any_t marker = hc->_marker; - CFIndex probe = keyHash & (hc->_bucketsNum - 1); - CFIndex probeskip = 1; // See RemoveValue() for notes before changing this value - CFIndex start = probe; - *match = kCFNotFound; - *nomatch = kCFNotFound; - for (;;) { - any_t currKey = keys[probe]; - if (marker == currKey) { /* empty */ - if (nomatch) *nomatch = probe; - return; - } else if (~marker == currKey) { /* deleted */ - if (nomatch) { - *nomatch = probe; - nomatch = NULL; - } - } else if (currKey == key || (cb->equal && INVOKE_CALLBACK3((Boolean (*)(any_t, any_t, any_pointer_t))cb->equal, currKey, key, hc->_context))) { - *match = probe; - return; - } - probe = probe + probeskip; - // This alternative to probe % buckets assumes that - // probeskip is always positive and less than the - // number of buckets. - if (hc->_bucketsNum <= probe) { - probe -= hc->_bucketsNum; - } - if (start == probe) { - return; - } - } -} - -static void __CFSetFindNewMarker(CFHashRef hc) { - any_t *keys = hc->_keys; - any_t newMarker; - CFIndex idx, nbuckets; - Boolean hit; - - nbuckets = hc->_bucketsNum; - newMarker = hc->_marker; - do { - newMarker--; - hit = false; - for (idx = 0; idx < nbuckets; idx++) { - if (newMarker == keys[idx] || ~newMarker == keys[idx]) { - hit = true; - break; - } - } - } while (hit); - for (idx = 0; idx < nbuckets; idx++) { - if (hc->_marker == keys[idx]) { - keys[idx] = newMarker; - } else if (~hc->_marker == keys[idx]) { - keys[idx] = ~newMarker; - } - } - ((struct __CFSet *)hc)->_marker = newMarker; -} - static Boolean __CFSetEqual(CFTypeRef cf1, CFTypeRef cf2) { - CFHashRef hc1 = (CFHashRef)cf1; - CFHashRef hc2 = (CFHashRef)cf2; - const CFSetKeyCallBacks *cb1, *cb2; - const CFSetValueCallBacks *vcb1, *vcb2; - any_t *keys; - CFIndex idx, nbuckets; - if (hc1 == hc2) return true; - if (hc1->_count != hc2->_count) return false; - cb1 = __CFSetGetKeyCallBacks(hc1); - cb2 = __CFSetGetKeyCallBacks(hc2); - if (cb1->equal != cb2->equal) return false; - vcb1 = __CFSetGetValueCallBacks(hc1); - vcb2 = __CFSetGetValueCallBacks(hc2); - if (vcb1->equal != vcb2->equal) return false; - if (0 == hc1->_bucketsUsed) return true; /* after function comparison! */ - keys = hc1->_keys; - nbuckets = hc1->_bucketsNum; - for (idx = 0; idx < nbuckets; idx++) { - if (hc1->_marker != keys[idx] && ~hc1->_marker != keys[idx]) { -#if CFDictionary - const_any_pointer_t value; - if (!CFSetGetValueIfPresent(hc2, (any_pointer_t)keys[idx], &value)) return false; - if (hc1->_values[idx] != (any_t)value) { - if (NULL == vcb1->equal) return false; - if (!INVOKE_CALLBACK3((Boolean (*)(any_t, any_t, any_pointer_t))vcb1->equal, hc1->_values[idx], (any_t)value, hc1->_context)) return false; - } -#endif -#if CFSet - const_any_pointer_t value; - if (!CFSetGetValueIfPresent(hc2, (any_pointer_t)keys[idx], &value)) return false; -#endif -#if CFBag - if (hc1->_values[idx] != CFSetGetCountOfValue(hc2, (any_pointer_t)keys[idx])) return false; -#endif - } - } - return true; + return __CFBasicHashEqual((CFBasicHashRef)cf1, (CFBasicHashRef)cf2); } static CFHashCode __CFSetHash(CFTypeRef cf) { - CFHashRef hc = (CFHashRef)cf; - return hc->_count; + return __CFBasicHashHash((CFBasicHashRef)cf); } static CFStringRef __CFSetCopyDescription(CFTypeRef cf) { - CFHashRef hc = (CFHashRef)cf; - CFAllocatorRef allocator; - const CFSetKeyCallBacks *cb; - const CFSetValueCallBacks *vcb; - any_t *keys; - CFIndex idx, nbuckets; - CFMutableStringRef result; - cb = __CFSetGetKeyCallBacks(hc); - vcb = __CFSetGetValueCallBacks(hc); - keys = hc->_keys; - nbuckets = hc->_bucketsNum; - allocator = CFGetAllocator(hc); - result = CFStringCreateMutable(allocator, 0); - const char *type = "?"; - switch (__CFHashGetType(hc)) { - case __kCFHashImmutable: type = "immutable"; break; - case __kCFHashMutable: type = "mutable"; break; - } - CFStringAppendFormat(result, NULL, CFSTR("{type = %s, count = %u, capacity = %u, pairs = (\n"), cf, allocator, type, hc->_count, hc->_bucketsCap); - for (idx = 0; idx < nbuckets; idx++) { - if (__CFHashKeyIsValue(hc, keys[idx])) { - CFStringRef kDesc = NULL, vDesc = NULL; - if (NULL != cb->copyDescription) { - kDesc = (CFStringRef)INVOKE_CALLBACK2(((CFStringRef (*)(any_t, any_pointer_t))cb->copyDescription), keys[idx], hc->_context); - } - if (NULL != vcb->copyDescription) { - vDesc = (CFStringRef)INVOKE_CALLBACK2(((CFStringRef (*)(any_t, any_pointer_t))vcb->copyDescription), hc->_values[idx], hc->_context); - } -#if CFDictionary - if (NULL != kDesc && NULL != vDesc) { - CFStringAppendFormat(result, NULL, CFSTR("\t%u : %@ = %@\n"), idx, kDesc, vDesc); - CFRelease(kDesc); - CFRelease(vDesc); - } else if (NULL != kDesc) { - CFStringAppendFormat(result, NULL, CFSTR("\t%u : %@ = <%p>\n"), idx, kDesc, hc->_values[idx]); - CFRelease(kDesc); - } else if (NULL != vDesc) { - CFStringAppendFormat(result, NULL, CFSTR("\t%u : <%p> = %@\n"), idx, keys[idx], vDesc); - CFRelease(vDesc); - } else { - CFStringAppendFormat(result, NULL, CFSTR("\t%u : <%p> = <%p>\n"), idx, keys[idx], hc->_values[idx]); - } -#endif -#if CFSet - if (NULL != kDesc) { - CFStringAppendFormat(result, NULL, CFSTR("\t%u : %@\n"), idx, kDesc); - CFRelease(kDesc); - } else { - CFStringAppendFormat(result, NULL, CFSTR("\t%u : <%p>\n"), idx, keys[idx]); - } -#endif -#if CFBag - if (NULL != kDesc) { - CFStringAppendFormat(result, NULL, CFSTR("\t%u : %@ (%ld)\n"), idx, kDesc, hc->_values[idx]); - CFRelease(kDesc); - } else { - CFStringAppendFormat(result, NULL, CFSTR("\t%u : <%p> (%ld)\n"), idx, keys[idx], hc->_values[idx]); - } -#endif - } - } - CFStringAppend(result, CFSTR(")}")); - return result; + return __CFBasicHashCopyDescription((CFBasicHashRef)cf); } static void __CFSetDeallocate(CFTypeRef cf) { - CFMutableHashRef hc = (CFMutableHashRef)cf; - CFAllocatorRef allocator = __CFGetAllocator(hc); - const CFSetKeyCallBacks *cb = __CFSetGetKeyCallBacks(hc); - const CFSetValueCallBacks *vcb = __CFSetGetValueCallBacks(hc); - - // mark now in case any callout somehow tries to add an entry back in - markFinalized(cf); - if (vcb->release || cb->release) { - any_t *keys = hc->_keys; - CFIndex idx, nbuckets = hc->_bucketsNum; - for (idx = 0; idx < nbuckets; idx++) { - any_t oldkey = keys[idx]; - if (hc->_marker != oldkey && ~hc->_marker != oldkey) { - if (vcb->release) { - INVOKE_CALLBACK3(((void (*)(CFAllocatorRef, any_t, any_pointer_t))vcb->release), allocator, hc->_values[idx], hc->_context); - } - if (cb->release) { - INVOKE_CALLBACK3(((void (*)(CFAllocatorRef, any_t, any_pointer_t))cb->release), allocator, oldkey, hc->_context); - } - } - } - } - - if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { - // return early so that contents are preserved after finalization - return; - } - - _CFAllocatorDeallocateGC(allocator, hc->_keys); -#if CFDictionary || CFBag - _CFAllocatorDeallocateGC(allocator, hc->_values); -#endif - hc->_keys = NULL; - hc->_values = NULL; - hc->_count = 0; // GC: also zero count, so the hc will appear empty. - hc->_bucketsUsed = 0; - hc->_bucketsNum = 0; + __CFBasicHashDeallocate((CFBasicHashRef)cf); } static CFTypeID __kCFSetTypeID = _kCFRuntimeNotATypeID; @@ -658,123 +125,183 @@ static const CFRuntimeClass __CFSetClass = { __CFSetCopyDescription }; -__private_extern__ void __CFSetInitialize(void) { - __kCFHashTypeID = _CFRuntimeRegisterClass(&__CFSetClass); -} - CFTypeID CFSetGetTypeID(void) { - return __kCFHashTypeID; + if (_kCFRuntimeNotATypeID == __kCFSetTypeID) __kCFSetTypeID = _CFRuntimeRegisterClass(&__CFSetClass); + return __kCFSetTypeID; } -static CFMutableHashRef __CFSetInit(CFAllocatorRef allocator, CFOptionFlags flags, CFIndex capacity, const CFSetKeyCallBacks *keyCallBacks -#if CFDictionary -, const CFSetValueCallBacks *valueCallBacks -#endif -) { - struct __CFSet *hc; - CFIndex size; - __CFBitfieldSetValue(flags, 31, 2, 0); - CFOptionFlags xflags = 0; +static uintptr_t __CFSetCallback(CFBasicHashRef ht, uint8_t op, uintptr_t a1, uintptr_t a2, CFBasicHashCallbacks *cb) { + switch (op) { + case kCFBasicHashCallbackOpCopyCallbacks: { + CFBasicHashCallbacks *newcb = NULL; + if (CF_IS_COLLECTABLE_ALLOCATOR((CFAllocatorRef)a1)) { + newcb = (CFBasicHashCallbacks *)auto_zone_allocate_object(auto_zone(), 10 * sizeof(void *), AUTO_MEMORY_UNSCANNED, true, false); + } else { + newcb = (CFBasicHashCallbacks *)CFAllocatorAllocate((CFAllocatorRef)a1, 10 * sizeof(void *), 0); + } + if (!newcb) HALT; + memmove(newcb, (void *)cb, 10 * sizeof(void *)); + return (uintptr_t)newcb; + } + case kCFBasicHashCallbackOpFreeCallbacks: { + if (CF_IS_COLLECTABLE_ALLOCATOR((CFAllocatorRef)a1)) { + auto_zone_release(auto_zone(), cb); + } else { + CFAllocatorDeallocate((CFAllocatorRef)a1, cb); + } + return 0; + } + case kCFBasicHashCallbackOpRetainValue: { + const_any_pointer_t (*value_retain)(CFAllocatorRef, const_any_pointer_t) = (const_any_pointer_t (*)(CFAllocatorRef, const_any_pointer_t))cb->context[0]; + if (NULL == value_retain) return a1; + return (uintptr_t)INVOKE_CALLBACK2(value_retain, CFGetAllocator(ht), (const_any_pointer_t)a1); + } + case kCFBasicHashCallbackOpRetainKey: { + const_any_pointer_t (*key_retain)(CFAllocatorRef, const_any_pointer_t) = (const_any_pointer_t (*)(CFAllocatorRef, const_any_pointer_t))cb->context[1]; + if (NULL == key_retain) return a1; + return (uintptr_t)INVOKE_CALLBACK2(key_retain, CFGetAllocator(ht), (const_any_pointer_t)a1); + } + case kCFBasicHashCallbackOpReleaseValue: { + void (*value_release)(CFAllocatorRef, const_any_pointer_t) = (void (*)(CFAllocatorRef, const_any_pointer_t))cb->context[2]; + if (NULL != value_release) INVOKE_CALLBACK2(value_release, CFGetAllocator(ht), (const_any_pointer_t)a1); + return 0; + } + case kCFBasicHashCallbackOpReleaseKey: { + void (*key_release)(CFAllocatorRef, const_any_pointer_t) = (void (*)(CFAllocatorRef, const_any_pointer_t))cb->context[3]; + if (NULL != key_release) INVOKE_CALLBACK2(key_release, CFGetAllocator(ht), (const_any_pointer_t)a1); + return 0; + } + case kCFBasicHashCallbackOpValueEqual: { + Boolean (*value_equal)(const_any_pointer_t, const_any_pointer_t) = (Boolean (*)(const_any_pointer_t, const_any_pointer_t))cb->context[4]; + if (NULL == value_equal) return (a1 == a2); + return INVOKE_CALLBACK2(value_equal, (const_any_pointer_t)a1, (const_any_pointer_t)a2) ? 1 : 0; + } + case kCFBasicHashCallbackOpKeyEqual: { + Boolean (*key_equal)(const_any_pointer_t, const_any_pointer_t) = (Boolean (*)(const_any_pointer_t, const_any_pointer_t))cb->context[5]; + if (NULL == key_equal) return (a1 == a2); + return INVOKE_CALLBACK2(key_equal, (const_any_pointer_t)a1, (const_any_pointer_t)a2) ? 1 : 0; + } + case kCFBasicHashCallbackOpHashKey: { + CFHashCode (*hash)(const_any_pointer_t) = (CFHashCode (*)(const_any_pointer_t))cb->context[6]; + if (NULL == hash) return a1; + return (uintptr_t)INVOKE_CALLBACK1(hash, (const_any_pointer_t)a1); + } + case kCFBasicHashCallbackOpDescribeValue: { + CFStringRef (*value_describe)(const_any_pointer_t) = (CFStringRef (*)(const_any_pointer_t))cb->context[7]; + if (NULL == value_describe) return (uintptr_t)CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<%p>"), (const_any_pointer_t)a1); + return (uintptr_t)INVOKE_CALLBACK1(value_describe, (const_any_pointer_t)a1); + } + case kCFBasicHashCallbackOpDescribeKey: { + CFStringRef (*key_describe)(const_any_pointer_t) = (CFStringRef (*)(const_any_pointer_t))cb->context[8]; + if (NULL == key_describe) return (uintptr_t)CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<%p>"), (const_any_pointer_t)a1); + return (uintptr_t)INVOKE_CALLBACK1(key_describe, (const_any_pointer_t)a1); + } + } + return 0; +} + +static CFBasicHashRef __CFSetCreateGeneric(CFAllocatorRef allocator, const CFHashKeyCallBacks *keyCallBacks, const CFHashValueCallBacks *valueCallBacks, Boolean useValueCB) { + + CFBasicHashCallbacks *cb = NULL; + CFOptionFlags flags = kCFBasicHashLinearHashing; // kCFBasicHashExponentialHashing + flags |= (CFDictionary ? kCFBasicHashHasKeys : 0) | (CFBag ? kCFBasicHashHasCounts : 0); + + const_any_pointer_t (*key_retain)(CFAllocatorRef, const_any_pointer_t) = NULL; + void (*key_release)(CFAllocatorRef, const_any_pointer_t) = NULL; + const_any_pointer_t (*value_retain)(CFAllocatorRef, const_any_pointer_t) = NULL; + void (*value_release)(CFAllocatorRef, const_any_pointer_t) = NULL; + Boolean std_cb = false; + if ((NULL == keyCallBacks || (keyCallBacks && 0 == memcmp(&__kCFNullSetKeyCallBacks, keyCallBacks, sizeof(__kCFNullSetKeyCallBacks)))) + && (!useValueCB || (NULL == valueCallBacks || (valueCallBacks && 0 == memcmp(&__kCFNullSetValueCallBacks, valueCallBacks, sizeof(__kCFNullSetValueCallBacks)))))) { + cb = (CFBasicHashCallbacks *)& CFBasicHashNullCallbacks; + } else if ((&kCFTypeSetKeyCallBacks == keyCallBacks || (keyCallBacks && 0 == memcmp(&kCFTypeSetKeyCallBacks, keyCallBacks, sizeof(kCFTypeSetKeyCallBacks)))) + && (!useValueCB || (&kCFTypeSetValueCallBacks == valueCallBacks || (valueCallBacks && 0 == memcmp(&kCFTypeSetValueCallBacks, valueCallBacks, sizeof(kCFTypeSetValueCallBacks)))))) { + std_cb = true; + cb = (CFBasicHashCallbacks *)& CFBasicHashStandardCallbacks; + } else { + Boolean (*key_equal)(const_any_pointer_t, const_any_pointer_t) = NULL; + Boolean (*value_equal)(const_any_pointer_t, const_any_pointer_t) = NULL; + CFStringRef (*key_describe)(const_any_pointer_t) = NULL; + CFStringRef (*value_describe)(const_any_pointer_t) = NULL; + CFHashCode (*hash_key)(const_any_pointer_t) = NULL; + key_retain = keyCallBacks ? keyCallBacks->retain : NULL; + key_release = keyCallBacks ? keyCallBacks->release : NULL; + key_equal = keyCallBacks ? keyCallBacks->equal : NULL; + key_describe = keyCallBacks ? keyCallBacks->copyDescription : NULL; + if (useValueCB) { + value_retain = valueCallBacks ? valueCallBacks->retain : NULL; + value_release = valueCallBacks ? valueCallBacks->release : NULL; + value_equal = valueCallBacks ? valueCallBacks->equal : NULL; + value_describe = valueCallBacks ? valueCallBacks->copyDescription : NULL; + } else { + value_retain = key_retain; + value_release = key_release; + value_equal = key_equal; + value_describe = key_describe; + } + hash_key = keyCallBacks ? keyCallBacks->hash : NULL; + FAULT_CALLBACK((void **)&key_retain); + FAULT_CALLBACK((void **)&key_release); + FAULT_CALLBACK((void **)&value_retain); + FAULT_CALLBACK((void **)&value_release); + FAULT_CALLBACK((void **)&key_equal); + FAULT_CALLBACK((void **)&value_equal); + FAULT_CALLBACK((void **)&key_describe); + FAULT_CALLBACK((void **)&value_describe); + FAULT_CALLBACK((void **)&hash_key); + + CFBasicHashCallbacks *newcb = NULL; + if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { + newcb = (CFBasicHashCallbacks *)auto_zone_allocate_object(auto_zone(), 10 * sizeof(void *), AUTO_MEMORY_UNSCANNED, true, false); + } else { + newcb = (CFBasicHashCallbacks *)CFAllocatorAllocate(allocator, 10 * sizeof(void *), 0); + } + if (!newcb) HALT; + newcb->func = (CFBasicHashCallbackType)__CFSetCallback; + newcb->context[0] = (uintptr_t)value_retain; + newcb->context[1] = (uintptr_t)key_retain; + newcb->context[2] = (uintptr_t)value_release; + newcb->context[3] = (uintptr_t)key_release; + newcb->context[4] = (uintptr_t)value_equal; + newcb->context[5] = (uintptr_t)key_equal; + newcb->context[6] = (uintptr_t)hash_key; + newcb->context[7] = (uintptr_t)value_describe; + newcb->context[8] = (uintptr_t)key_describe; + cb = newcb; + } + if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { - // preserve NULL for key or value CB, otherwise fix up. - if (!keyCallBacks || (keyCallBacks->retain == NULL && keyCallBacks->release == NULL)) { - xflags = __kCFHashWeakKeys; + if (std_cb || value_retain != NULL || value_release != NULL) { + flags |= kCFBasicHashStrongValues; } -#if CFDictionary - if (!valueCallBacks || (valueCallBacks->retain == NULL && valueCallBacks->release == NULL)) { - xflags |= __kCFHashWeakValues; + if (std_cb || key_retain != NULL || key_release != NULL) { + flags |= kCFBasicHashStrongKeys; } -#endif -#if CFBag - xflags |= __kCFHashWeakValues; -#endif - } - if (__CFSetKeyCallBacksMatchNull(keyCallBacks)) { - __CFBitfieldSetValue(flags, 3, 2, __kCFHashHasNullCallBacks); - } else if (__CFSetKeyCallBacksMatchCFType(keyCallBacks)) { - __CFBitfieldSetValue(flags, 3, 2, __kCFHashHasCFTypeCallBacks); - } else { - __CFBitfieldSetValue(flags, 3, 2, __kCFHashHasCustomCallBacks); - } -#if CFDictionary - if (__CFSetValueCallBacksMatchNull(valueCallBacks)) { - __CFBitfieldSetValue(flags, 5, 4, __kCFHashHasNullCallBacks); - } else if (__CFSetValueCallBacksMatchCFType(valueCallBacks)) { - __CFBitfieldSetValue(flags, 5, 4, __kCFHashHasCFTypeCallBacks); - } else { - __CFBitfieldSetValue(flags, 5, 4, __kCFHashHasCustomCallBacks); - } -#endif - size = __CFSetGetSizeOfType(flags) - sizeof(CFRuntimeBase); - hc = (struct __CFSet *)_CFRuntimeCreateInstance(allocator, __kCFHashTypeID, size, NULL); - if (NULL == hc) { - return NULL; } - hc->_count = 0; - hc->_bucketsUsed = 0; - hc->_marker = (any_t)0xa1b1c1d3; - hc->_context = NULL; - hc->_deletes = 0; - hc->_mutations = 1; - hc->_xflags = xflags | flags; - switch (__CFBitfieldGetValue(flags, 1, 0)) { - case __kCFHashImmutable: - if (__CFOASafe) __CFSetLastAllocationEventName(hc, "CFSet (immutable)"); - break; - case __kCFHashMutable: - if (__CFOASafe) __CFSetLastAllocationEventName(hc, "CFSet (mutable-variable)"); - break; - } - hc->_bucketsCap = __CFHashRoundUpCapacity(1); - hc->_bucketsNum = 0; - hc->_keys = NULL; - hc->_values = NULL; - if (__kCFHashHasCustomCallBacks == __CFBitfieldGetValue(flags, 3, 2)) { - CFSetKeyCallBacks *cb = (CFSetKeyCallBacks *)__CFSetGetKeyCallBacks((CFHashRef)hc); - *cb = *keyCallBacks; - FAULT_CALLBACK((void **)&(cb->retain)); - FAULT_CALLBACK((void **)&(cb->release)); - FAULT_CALLBACK((void **)&(cb->copyDescription)); - FAULT_CALLBACK((void **)&(cb->equal)); - FAULT_CALLBACK((void **)&(cb->hash)); - } -#if CFDictionary - if (__kCFHashHasCustomCallBacks == __CFBitfieldGetValue(flags, 5, 4)) { - CFSetValueCallBacks *vcb = (CFSetValueCallBacks *)__CFSetGetValueCallBacks((CFHashRef)hc); - *vcb = *valueCallBacks; - FAULT_CALLBACK((void **)&(vcb->retain)); - FAULT_CALLBACK((void **)&(vcb->release)); - FAULT_CALLBACK((void **)&(vcb->copyDescription)); - FAULT_CALLBACK((void **)&(vcb->equal)); - } -#endif - return hc; + + return CFBasicHashCreate(allocator, flags, cb); } #if CFDictionary -CFHashRef CFSetCreate(CFAllocatorRef allocator, const_any_pointer_t *keys, const_any_pointer_t *values, CFIndex numValues, const CFSetKeyCallBacks *keyCallBacks, const CFSetValueCallBacks *valueCallBacks) { +CFHashRef CFSetCreate(CFAllocatorRef allocator, const_any_pointer_t *klist, const_any_pointer_t *vlist, CFIndex numValues, const CFSetKeyCallBacks *keyCallBacks, const CFSetValueCallBacks *valueCallBacks) { #endif #if CFSet || CFBag -CFHashRef CFSetCreate(CFAllocatorRef allocator, const_any_pointer_t *keys, CFIndex numValues, const CFSetKeyCallBacks *keyCallBacks) { +CFHashRef CFSetCreate(CFAllocatorRef allocator, const_any_pointer_t *klist, CFIndex numValues, const CFSetKeyCallBacks *keyCallBacks) { + const_any_pointer_t *vlist = klist; + const CFSetValueCallBacks *valueCallBacks = 0; #endif + CFTypeID typeID = CFSetGetTypeID(); CFAssert2(0 <= numValues, __kCFLogAssertion, "%s(): numValues (%ld) cannot be less than zero", __PRETTY_FUNCTION__, numValues); -#if CFDictionary - CFMutableHashRef hc = __CFSetInit(allocator, __kCFHashImmutable, numValues, keyCallBacks, valueCallBacks); -#endif -#if CFSet || CFBag - CFMutableHashRef hc = __CFSetInit(allocator, __kCFHashImmutable, numValues, keyCallBacks); -#endif - __CFBitfieldSetValue(hc->_xflags, 1, 0, __kCFHashMutable); + CFBasicHashRef ht = __CFSetCreateGeneric(allocator, keyCallBacks, valueCallBacks, CFDictionary); + if (0 < numValues) CFBasicHashSetCapacity(ht, numValues); for (CFIndex idx = 0; idx < numValues; idx++) { -#if CFDictionary - CFSetAddValue(hc, keys[idx], values[idx]); -#endif -#if CFSet || CFBag - CFSetAddValue(hc, keys[idx]); -#endif + CFBasicHashAddValue(ht, (uintptr_t)klist[idx], (uintptr_t)vlist[idx]); } - __CFBitfieldSetValue(hc->_xflags, 1, 0, __kCFHashImmutable); - return (CFHashRef)hc; + CFBasicHashMakeImmutable(ht); + *(uintptr_t *)ht = __CFISAForTypeID(typeID); + _CFRuntimeSetInstanceTypeID(ht, typeID); + if (__CFOASafe) __CFSetLastAllocationEventName(ht, "CFSet (immutable)"); + return (CFHashRef)ht; } #if CFDictionary @@ -782,158 +309,90 @@ CFMutableHashRef CFSetCreateMutable(CFAllocatorRef allocator, CFIndex capacity, #endif #if CFSet || CFBag CFMutableHashRef CFSetCreateMutable(CFAllocatorRef allocator, CFIndex capacity, const CFSetKeyCallBacks *keyCallBacks) { + const CFSetValueCallBacks *valueCallBacks = 0; #endif + CFTypeID typeID = CFSetGetTypeID(); CFAssert2(0 <= capacity, __kCFLogAssertion, "%s(): capacity (%ld) cannot be less than zero", __PRETTY_FUNCTION__, capacity); -#if CFDictionary - CFMutableHashRef hc = __CFSetInit(allocator, __kCFHashMutable, capacity, keyCallBacks, valueCallBacks); -#endif -#if CFSet || CFBag - CFMutableHashRef hc = __CFSetInit(allocator, __kCFHashMutable, capacity, keyCallBacks); -#endif - return hc; + CFBasicHashRef ht = __CFSetCreateGeneric(allocator, keyCallBacks, valueCallBacks, CFDictionary); + *(uintptr_t *)ht = __CFISAForTypeID(typeID); + _CFRuntimeSetInstanceTypeID(ht, typeID); + if (__CFOASafe) __CFSetLastAllocationEventName(ht, "CFSet (mutable)"); + return (CFMutableHashRef)ht; } -#if CFDictionary || CFSet -// does not have Add semantics for Bag; it has Set semantics ... is that best? -static void __CFSetGrow(CFMutableHashRef hc, CFIndex numNewValues); - -// This creates a hc which is for CFTypes or NSObjects, with a CFRetain style ownership transfer; -// the hc does not take a retain (since it claims 1), and the caller does not need to release the inserted objects (since we do it). -// The incoming objects must also be collectable if allocated out of a collectable allocator - and are neither released nor retained. -#if CFDictionary -CFHashRef _CFSetCreate_ex(CFAllocatorRef allocator, Boolean isMutable, const_any_pointer_t *keys, const_any_pointer_t *values, CFIndex numValues) { -#endif -#if CFSet || CFBag -CFHashRef _CFSetCreate_ex(CFAllocatorRef allocator, Boolean isMutable, const_any_pointer_t *keys, CFIndex numValues) { -#endif - CFAssert2(0 <= numValues, __kCFLogAssertion, "%s(): numValues (%ld) cannot be less than zero", __PRETTY_FUNCTION__, numValues); -#if CFDictionary - CFMutableHashRef hc = __CFSetInit(allocator, __kCFHashMutable, numValues, &kCFTypeSetKeyCallBacks, &kCFTypeSetValueCallBacks); -#endif -#if CFSet || CFBag - CFMutableHashRef hc = __CFSetInit(allocator, __kCFHashMutable, numValues, &kCFTypeSetKeyCallBacks); -#endif - __CFSetGrow(hc, numValues); - for (CFIndex idx = 0; idx < numValues; idx++) { - CFIndex match, nomatch; - __CFSetFindBuckets2(hc, (any_t)keys[idx], &match, &nomatch); - if (kCFNotFound == match) { - CFAllocatorRef allocator = __CFGetAllocator(hc); - any_t newKey = (any_t)keys[idx]; - if (__CFHashKeyIsMagic(hc, newKey)) { - __CFSetFindNewMarker(hc); - } - if (hc->_keys[nomatch] == ~hc->_marker) { - hc->_deletes--; - } - CFAllocatorRef keysAllocator = (hc->_xflags & __kCFHashWeakKeys) ? kCFAllocatorNull : allocator; - CF_WRITE_BARRIER_ASSIGN(keysAllocator, hc->_keys[nomatch], newKey); -#if CFDictionary - any_t newValue = (any_t)values[idx]; - CFAllocatorRef valuesAllocator = (hc->_xflags & __kCFHashWeakValues) ? kCFAllocatorNull : allocator; - CF_WRITE_BARRIER_ASSIGN(valuesAllocator, hc->_values[nomatch], newValue); -#endif -#if CFBag - hc->_values[nomatch] = 1; -#endif - hc->_bucketsUsed++; - hc->_count++; - } else { - CFAllocatorRef allocator = __CFGetAllocator(hc); +CFHashRef CFSetCreateCopy(CFAllocatorRef allocator, CFHashRef other) { + CFTypeID typeID = CFSetGetTypeID(); + CFAssert1(other, __kCFLogAssertion, "%s(): other CFSet cannot be NULL", __PRETTY_FUNCTION__); + __CFGenericValidateType(other, typeID); + CFBasicHashRef ht = NULL; + if (CF_IS_OBJC(typeID, other)) { + CFIndex numValues = CFSetGetCount(other); + const_any_pointer_t vbuffer[256], kbuffer[256]; + const_any_pointer_t *vlist = (numValues <= 256) ? vbuffer : (const_any_pointer_t *)CFAllocatorAllocate(kCFAllocatorSystemDefault, numValues * sizeof(const_any_pointer_t), 0); #if CFSet || CFBag - any_t oldKey = hc->_keys[match]; - any_t newKey = (any_t)keys[idx]; - CFAllocatorRef keysAllocator = (hc->_xflags & __kCFHashWeakKeys) ? kCFAllocatorNull : allocator; - CF_WRITE_BARRIER_ASSIGN(keysAllocator, hc->_keys[match], ~hc->_marker); - if (__CFHashKeyIsMagic(hc, newKey)) { - __CFSetFindNewMarker(hc); - } - CF_WRITE_BARRIER_ASSIGN(keysAllocator, hc->_keys[match], newKey); - RELEASEKEY(oldKey); + const_any_pointer_t *klist = vlist; + CFSetGetValues(other, vlist); #endif #if CFDictionary - any_t oldValue = hc->_values[match]; - any_t newValue = (any_t)values[idx]; - CFAllocatorRef valuesAllocator = (hc->_xflags & __kCFHashWeakValues) ? kCFAllocatorNull : allocator; - CF_WRITE_BARRIER_ASSIGN(valuesAllocator, hc->_values[match], newValue); - RELEASEVALUE(oldValue); + const_any_pointer_t *klist = (numValues <= 256) ? kbuffer : (const_any_pointer_t *)CFAllocatorAllocate(kCFAllocatorSystemDefault, numValues * sizeof(const_any_pointer_t), 0); + CFDictionaryGetKeysAndValues(other, klist, vlist); #endif + ht = __CFSetCreateGeneric(allocator, & kCFTypeSetKeyCallBacks, CFDictionary ? & kCFTypeSetValueCallBacks : NULL, CFDictionary); + if (0 < numValues) CFBasicHashSetCapacity(ht, numValues); + for (CFIndex idx = 0; idx < numValues; idx++) { + CFBasicHashAddValue(ht, (uintptr_t)klist[idx], (uintptr_t)vlist[idx]); } + if (klist != kbuffer && klist != vlist) CFAllocatorDeallocate(kCFAllocatorSystemDefault, klist); + if (vlist != vbuffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, vlist); + } else { + ht = CFBasicHashCreateCopy(allocator, (CFBasicHashRef)other); } - if (!isMutable) __CFBitfieldSetValue(hc->_xflags, 1, 0, __kCFHashImmutable); - return (CFHashRef)hc; -} -#endif - -CFHashRef CFSetCreateCopy(CFAllocatorRef allocator, CFHashRef other) { - CFMutableHashRef hc = CFSetCreateMutableCopy(allocator, CFSetGetCount(other), other); - __CFBitfieldSetValue(hc->_xflags, 1, 0, __kCFHashImmutable); - if (__CFOASafe) __CFSetLastAllocationEventName(hc, "CFSet (immutable)"); - return hc; + CFBasicHashMakeImmutable(ht); + *(uintptr_t *)ht = __CFISAForTypeID(typeID); + _CFRuntimeSetInstanceTypeID(ht, typeID); + if (__CFOASafe) __CFSetLastAllocationEventName(ht, "CFSet (immutable)"); + return (CFHashRef)ht; } CFMutableHashRef CFSetCreateMutableCopy(CFAllocatorRef allocator, CFIndex capacity, CFHashRef other) { - CFIndex numValues = CFSetGetCount(other); - const_any_pointer_t *list, buffer[256]; - list = (numValues <= 256) ? buffer : (const_any_pointer_t *)CFAllocatorAllocate(allocator, numValues * sizeof(const_any_pointer_t), 0); - if (list != buffer && __CFOASafe) __CFSetLastAllocationEventName(list, "CFSet (temp)"); -#if CFDictionary - const_any_pointer_t *vlist, vbuffer[256]; - vlist = (numValues <= 256) ? vbuffer : (const_any_pointer_t *)CFAllocatorAllocate(allocator, numValues * sizeof(const_any_pointer_t), 0); - if (vlist != vbuffer && __CFOASafe) __CFSetLastAllocationEventName(vlist, "CFSet (temp)"); -#endif + CFTypeID typeID = CFSetGetTypeID(); + CFAssert1(other, __kCFLogAssertion, "%s(): other CFSet cannot be NULL", __PRETTY_FUNCTION__); + __CFGenericValidateType(other, typeID); + CFAssert2(0 <= capacity, __kCFLogAssertion, "%s(): capacity (%ld) cannot be less than zero", __PRETTY_FUNCTION__, capacity); + CFBasicHashRef ht = NULL; + if (CF_IS_OBJC(typeID, other)) { + CFIndex numValues = CFSetGetCount(other); + const_any_pointer_t vbuffer[256], kbuffer[256]; + const_any_pointer_t *vlist = (numValues <= 256) ? vbuffer : (const_any_pointer_t *)CFAllocatorAllocate(kCFAllocatorSystemDefault, numValues * sizeof(const_any_pointer_t), 0); #if CFSet || CFBag - CFSetGetValues(other, list); + const_any_pointer_t *klist = vlist; + CFSetGetValues(other, vlist); #endif #if CFDictionary - CFSetGetKeysAndValues(other, list, vlist); + const_any_pointer_t *klist = (numValues <= 256) ? kbuffer : (const_any_pointer_t *)CFAllocatorAllocate(kCFAllocatorSystemDefault, numValues * sizeof(const_any_pointer_t), 0); + CFDictionaryGetKeysAndValues(other, klist, vlist); #endif - const CFSetKeyCallBacks *kcb; - const CFSetValueCallBacks *vcb; - if (CF_IS_OBJC(__kCFHashTypeID, other)) { - kcb = &kCFTypeSetKeyCallBacks; - vcb = &kCFTypeSetValueCallBacks; + ht = __CFSetCreateGeneric(allocator, & kCFTypeSetKeyCallBacks, CFDictionary ? & kCFTypeSetValueCallBacks : NULL, CFDictionary); + if (0 < numValues) CFBasicHashSetCapacity(ht, numValues); + for (CFIndex idx = 0; idx < numValues; idx++) { + CFBasicHashAddValue(ht, (uintptr_t)klist[idx], (uintptr_t)vlist[idx]); + } + if (klist != kbuffer && klist != vlist) CFAllocatorDeallocate(kCFAllocatorSystemDefault, klist); + if (vlist != vbuffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, vlist); } else { - kcb = __CFSetGetKeyCallBacks(other); - vcb = __CFSetGetValueCallBacks(other); - } -#if CFDictionary - CFMutableHashRef hc = __CFSetInit(allocator, __kCFHashMutable, capacity, kcb, vcb); -#endif -#if CFSet || CFBag - CFMutableHashRef hc = __CFSetInit(allocator, __kCFHashMutable, capacity, kcb); -#endif - if (0 == capacity) _CFSetSetCapacity(hc, numValues); - for (CFIndex idx = 0; idx < numValues; idx++) { -#if CFDictionary - CFSetAddValue(hc, list[idx], vlist[idx]); -#endif -#if CFSet || CFBag - CFSetAddValue(hc, list[idx]); -#endif + ht = CFBasicHashCreateCopy(allocator, (CFBasicHashRef)other); } - if (list != buffer) CFAllocatorDeallocate(allocator, list); -#if CFDictionary - if (vlist != vbuffer) CFAllocatorDeallocate(allocator, vlist); -#endif - return hc; -} - -// Used by NSHashTables/NSMapTables and KVO -void _CFSetSetContext(CFHashRef hc, any_pointer_t context) { - __CFGenericValidateType(hc, __kCFHashTypeID); - CF_WRITE_BARRIER_BASE_ASSIGN(__CFGetAllocator(hc), hc, hc->_context, context); -} - -any_pointer_t _CFSetGetContext(CFHashRef hc) { - __CFGenericValidateType(hc, __kCFHashTypeID); - return hc->_context; + *(uintptr_t *)ht = __CFISAForTypeID(typeID); + _CFRuntimeSetInstanceTypeID(ht, typeID); + if (__CFOASafe) __CFSetLastAllocationEventName(ht, "CFSet (mutable)"); + return (CFMutableHashRef)ht; } CFIndex CFSetGetCount(CFHashRef hc) { - if (CFDictionary || CFSet) CF_OBJC_FUNCDISPATCH0(__kCFHashTypeID, CFIndex, hc, "count"); - __CFGenericValidateType(hc, __kCFHashTypeID); - return hc->_count; + if (CFDictionary) CF_OBJC_FUNCDISPATCH0(__kCFSetTypeID, CFIndex, hc, "count"); + if (CFSet) CF_OBJC_FUNCDISPATCH0(__kCFSetTypeID, CFIndex, hc, "count"); + __CFGenericValidateType(hc, __kCFSetTypeID); + return CFBasicHashGetCount((CFBasicHashRef)hc); } #if CFDictionary @@ -942,12 +401,10 @@ CFIndex CFSetGetCountOfKey(CFHashRef hc, const_any_pointer_t key) { #if CFSet || CFBag CFIndex CFSetGetCountOfValue(CFHashRef hc, const_any_pointer_t key) { #endif - if (CFDictionary) CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID, CFIndex, hc, "countForKey:", key); - if (CFSet) CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID, CFIndex, hc, "countForObject:", key); - __CFGenericValidateType(hc, __kCFHashTypeID); - if (0 == hc->_bucketsUsed) return 0; - CFIndex match = __CFSetFindBuckets1(hc, (any_t)key); - return (kCFNotFound != match ? __CFHashGetOccurrenceCount(hc, match) : 0); + if (CFDictionary) CF_OBJC_FUNCDISPATCH1(__kCFSetTypeID, CFIndex, hc, "countForKey:", key); + if (CFSet) CF_OBJC_FUNCDISPATCH1(__kCFSetTypeID, CFIndex, hc, "countForObject:", key); + __CFGenericValidateType(hc, __kCFSetTypeID); + return CFBasicHashGetCountOfKey((CFBasicHashRef)hc, (uintptr_t)key); } #if CFDictionary @@ -956,74 +413,66 @@ Boolean CFSetContainsKey(CFHashRef hc, const_any_pointer_t key) { #if CFSet || CFBag Boolean CFSetContainsValue(CFHashRef hc, const_any_pointer_t key) { #endif - if (CFDictionary) CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID, char, hc, "containsKey:", key); - if (CFSet) CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID, char, hc, "containsObject:", key); - __CFGenericValidateType(hc, __kCFHashTypeID); - if (0 == hc->_bucketsUsed) return false; - CFIndex match = __CFSetFindBuckets1(hc, (any_t)key); - return (kCFNotFound != match ? true : false); + if (CFDictionary) CF_OBJC_FUNCDISPATCH1(__kCFSetTypeID, char, hc, "containsKey:", key); + if (CFSet) CF_OBJC_FUNCDISPATCH1(__kCFSetTypeID, char, hc, "containsObject:", key); + __CFGenericValidateType(hc, __kCFSetTypeID); + return (0 < CFBasicHashGetCountOfKey((CFBasicHashRef)hc, (uintptr_t)key)); } -#if CFDictionary -CFIndex CFSetGetCountOfValue(CFHashRef hc, const_any_pointer_t value) { - CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID, CFIndex, hc, "countForObject:", value); - __CFGenericValidateType(hc, __kCFHashTypeID); - if (0 == hc->_bucketsUsed) return 0; - any_t *keys = hc->_keys; - Boolean (*equal)(any_t, any_t, any_pointer_t) = (Boolean (*)(any_t, any_t, any_pointer_t))__CFSetGetValueCallBacks(hc)->equal; - CFIndex cnt = 0; - for (CFIndex idx = 0, nbuckets = hc->_bucketsNum; idx < nbuckets; idx++) { - if (__CFHashKeyIsValue(hc, keys[idx])) { - if ((hc->_values[idx] == (any_t)value) || (equal && INVOKE_CALLBACK3(equal, hc->_values[idx], (any_t)value, hc->_context))) { - cnt++; - } - } - } - return cnt; +const_any_pointer_t CFSetGetValue(CFHashRef hc, const_any_pointer_t key) { + if (CFDictionary) CF_OBJC_FUNCDISPATCH1(__kCFSetTypeID, const_any_pointer_t, hc, "objectForKey:", key); + if (CFSet) CF_OBJC_FUNCDISPATCH1(__kCFSetTypeID, const_any_pointer_t, hc, "member:", key); + __CFGenericValidateType(hc, __kCFSetTypeID); + CFBasicHashBucket bkt = CFBasicHashFindBucket((CFBasicHashRef)hc, (uintptr_t)key); + return (0 < bkt.count ? (const_any_pointer_t)bkt.weak_value : 0); } -Boolean CFSetContainsValue(CFHashRef hc, const_any_pointer_t value) { - CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID, char, hc, "containsObject:", value); - __CFGenericValidateType(hc, __kCFHashTypeID); - if (0 == hc->_bucketsUsed) return false; - any_t *keys = hc->_keys; - Boolean (*equal)(any_t, any_t, any_pointer_t) = (Boolean (*)(any_t, any_t, any_pointer_t))__CFSetGetValueCallBacks(hc)->equal; - for (CFIndex idx = 0, nbuckets = hc->_bucketsNum; idx < nbuckets; idx++) { - if (__CFHashKeyIsValue(hc, keys[idx])) { - if ((hc->_values[idx] == (any_t)value) || (equal && INVOKE_CALLBACK3(equal, hc->_values[idx], (any_t)value, hc->_context))) { - return true; +Boolean CFSetGetValueIfPresent(CFHashRef hc, const_any_pointer_t key, const_any_pointer_t *value) { + if (CFDictionary) CF_OBJC_FUNCDISPATCH2(__kCFSetTypeID, Boolean, hc, "_getValue:forKey:", (any_t *)value, key); + if (CFSet) CF_OBJC_FUNCDISPATCH2(__kCFSetTypeID, Boolean, hc, "_getValue:forObj:", (any_t *)value, key); + __CFGenericValidateType(hc, __kCFSetTypeID); + CFBasicHashBucket bkt = CFBasicHashFindBucket((CFBasicHashRef)hc, (uintptr_t)key); + if (0 < bkt.count) { + if (value) { + if (kCFUseCollectableAllocator && (CFBasicHashGetFlags((CFBasicHashRef)hc) & kCFBasicHashStrongValues)) { + __CFAssignWithWriteBarrier((void **)value, (void *)bkt.weak_value); + } else { + *value = (const_any_pointer_t)bkt.weak_value; } } + return true; } return false; } -#endif -const_any_pointer_t CFSetGetValue(CFHashRef hc, const_any_pointer_t key) { - if (CFDictionary) CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID, const_any_pointer_t, hc, "objectForKey:", key); - if (CFSet) CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID, const_any_pointer_t, hc, "member:", key); - __CFGenericValidateType(hc, __kCFHashTypeID); - if (0 == hc->_bucketsUsed) return 0; - CFIndex match = __CFSetFindBuckets1(hc, (any_t)key); - return (kCFNotFound != match ? (const_any_pointer_t)(CFDictionary ? hc->_values[match] : hc->_keys[match]) : 0); +#if CFDictionary +CFIndex CFDictionaryGetCountOfValue(CFHashRef hc, const_any_pointer_t value) { + CF_OBJC_FUNCDISPATCH1(__kCFSetTypeID, CFIndex, hc, "countForObject:", value); + __CFGenericValidateType(hc, __kCFSetTypeID); + return CFBasicHashGetCountOfValue((CFBasicHashRef)hc, (uintptr_t)value); } -Boolean CFSetGetValueIfPresent(CFHashRef hc, const_any_pointer_t key, const_any_pointer_t *value) { - if (CFDictionary) CF_OBJC_FUNCDISPATCH2(__kCFHashTypeID, Boolean, hc, "_getValue:forKey:", (any_t *)value, key); - if (CFSet) CF_OBJC_FUNCDISPATCH2(__kCFHashTypeID, Boolean, hc, "_getValue:forObj:", (any_t *)value, key); - __CFGenericValidateType(hc, __kCFHashTypeID); - if (0 == hc->_bucketsUsed) return false; - CFIndex match = __CFSetFindBuckets1(hc, (any_t)key); - return (kCFNotFound != match ? ((value ? __CFObjCStrongAssign((const_any_pointer_t)(CFDictionary ? hc->_values[match] : hc->_keys[match]), value) : 0), true) : false); +Boolean CFDictionaryContainsValue(CFHashRef hc, const_any_pointer_t value) { + CF_OBJC_FUNCDISPATCH1(__kCFSetTypeID, char, hc, "containsObject:", value); + __CFGenericValidateType(hc, __kCFSetTypeID); + return (0 < CFBasicHashGetCountOfValue((CFBasicHashRef)hc, (uintptr_t)value)); } -#if CFDictionary -Boolean CFSetGetKeyIfPresent(CFHashRef hc, const_any_pointer_t key, const_any_pointer_t *actualkey) { - CF_OBJC_FUNCDISPATCH2(__kCFHashTypeID, Boolean, hc, "getActualKey:forKey:", actualkey, key); - __CFGenericValidateType(hc, __kCFHashTypeID); - if (0 == hc->_bucketsUsed) return false; - CFIndex match = __CFSetFindBuckets1(hc, (any_t)key); - return (kCFNotFound != match ? ((actualkey ? __CFObjCStrongAssign((const_any_pointer_t)hc->_keys[match], actualkey) : NULL), true) : false); +CF_EXPORT Boolean CFDictionaryGetKeyIfPresent(CFHashRef hc, const_any_pointer_t key, const_any_pointer_t *actualkey) { + CF_OBJC_FUNCDISPATCH2(__kCFSetTypeID, Boolean, hc, "getActualKey:forKey:", actualkey, key); + __CFGenericValidateType(hc, __kCFSetTypeID); + CFBasicHashBucket bkt = CFBasicHashFindBucket((CFBasicHashRef)hc, (uintptr_t)key); + if (0 < bkt.count) { + if (actualkey) { + if (kCFUseCollectableAllocator && (CFBasicHashGetFlags((CFBasicHashRef)hc) & kCFBasicHashStrongKeys)) { + __CFAssignWithWriteBarrier((void **)actualkey, (void *)bkt.weak_key); + } else { + *actualkey = (const_any_pointer_t)bkt.weak_key; + } + } + return true; + } + return false; } #endif @@ -1034,183 +483,113 @@ void CFSetGetKeysAndValues(CFHashRef hc, const_any_pointer_t *keybuf, const_any_ void CFSetGetValues(CFHashRef hc, const_any_pointer_t *keybuf) { const_any_pointer_t *valuebuf = 0; #endif - if (CFDictionary) CF_OBJC_FUNCDISPATCH2(__kCFHashTypeID, void, hc, "getObjects:andKeys:", (any_t *)valuebuf, (any_t *)keybuf); - if (CFSet) CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID, void, hc, "getObjects:", (any_t *)keybuf); - __CFGenericValidateType(hc, __kCFHashTypeID); - if (CF_USING_COLLECTABLE_MEMORY) { - // GC: speculatively issue a write-barrier on the copied to buffers - __CFObjCWriteBarrierRange(keybuf, hc->_count * sizeof(any_t)); - __CFObjCWriteBarrierRange(valuebuf, hc->_count * sizeof(any_t)); - } - any_t *keys = hc->_keys; - for (CFIndex idx = 0, nbuckets = hc->_bucketsNum; idx < nbuckets; idx++) { - if (__CFHashKeyIsValue(hc, keys[idx])) { - for (CFIndex cnt = __CFHashGetOccurrenceCount(hc, idx); cnt--;) { - if (keybuf) *keybuf++ = (const_any_pointer_t)keys[idx]; - if (valuebuf) *valuebuf++ = (const_any_pointer_t)hc->_values[idx]; - } - } - } -} - -#if CFDictionary || CFSet -unsigned long _CFSetFastEnumeration(CFHashRef hc, struct __objcFastEnumerationStateEquivalent *state, void *stackbuffer, unsigned long count) { - /* copy as many as count items over */ - if (0 == state->state) { /* first time */ - state->mutationsPtr = (unsigned long *)&hc->_mutations; - } - state->itemsPtr = (unsigned long *)stackbuffer; - CFIndex cnt = 0; - any_t *keys = hc->_keys; - for (CFIndex idx = (CFIndex)state->state, nbuckets = hc->_bucketsNum; idx < nbuckets && cnt < (CFIndex)count; idx++) { - if (__CFHashKeyIsValue(hc, keys[idx])) { - state->itemsPtr[cnt++] = (unsigned long)keys[idx]; - } - state->state++; + if (CFDictionary) CF_OBJC_FUNCDISPATCH2(__kCFSetTypeID, void, hc, "getObjects:andKeys:", (any_t *)valuebuf, (any_t *)keybuf); + if (CFSet) CF_OBJC_FUNCDISPATCH1(__kCFSetTypeID, void, hc, "getObjects:", (any_t *)keybuf); + __CFGenericValidateType(hc, __kCFSetTypeID); + if (kCFUseCollectableAllocator) { + CFOptionFlags flags = CFBasicHashGetFlags((CFBasicHashRef)hc); + __block const_any_pointer_t *keys = keybuf, *values = valuebuf; + CFBasicHashApply((CFBasicHashRef)hc, ^(CFBasicHashBucket bkt) { + for (CFIndex cnt = bkt.count; cnt--;) { + if (keybuf && (flags & kCFBasicHashStrongKeys)) { __CFAssignWithWriteBarrier((void **)keys, (void *)bkt.weak_key); keys++; } + if (keybuf && !(flags & kCFBasicHashStrongKeys)) { *keys++ = (const_any_pointer_t)bkt.weak_key; } + if (valuebuf && (flags & kCFBasicHashStrongValues)) { __CFAssignWithWriteBarrier((void **)values, (void *)bkt.weak_value); values++; } + if (valuebuf && !(flags & kCFBasicHashStrongValues)) { *values++ = (const_any_pointer_t)bkt.weak_value; } + } + return (Boolean)true; + }); + } else { + CFBasicHashGetElements((CFBasicHashRef)hc, CFSetGetCount(hc), (uintptr_t *)valuebuf, NULL, (uintptr_t *)keybuf, NULL); } - return cnt; } -#endif void CFSetApplyFunction(CFHashRef hc, CFSetApplierFunction applier, any_pointer_t context) { FAULT_CALLBACK((void **)&(applier)); - if (CFDictionary) CF_OBJC_FUNCDISPATCH2(__kCFHashTypeID, void, hc, "_apply:context:", applier, context); - if (CFSet) CF_OBJC_FUNCDISPATCH2(__kCFHashTypeID, void, hc, "_applyValues:context:", applier, context); - __CFGenericValidateType(hc, __kCFHashTypeID); - any_t *keys = hc->_keys; - for (CFIndex idx = 0, nbuckets = hc->_bucketsNum; idx < nbuckets; idx++) { - if (__CFHashKeyIsValue(hc, keys[idx])) { - for (CFIndex cnt = __CFHashGetOccurrenceCount(hc, idx); cnt--;) { + if (CFDictionary) CF_OBJC_FUNCDISPATCH2(__kCFSetTypeID, void, hc, "_apply:context:", applier, context); + if (CFSet) CF_OBJC_FUNCDISPATCH2(__kCFSetTypeID, void, hc, "_applyValues:context:", applier, context); + __CFGenericValidateType(hc, __kCFSetTypeID); + CFBasicHashApply((CFBasicHashRef)hc, ^(CFBasicHashBucket bkt) { #if CFDictionary - INVOKE_CALLBACK3(applier, (const_any_pointer_t)keys[idx], (const_any_pointer_t)hc->_values[idx], context); + INVOKE_CALLBACK3(applier, (const_any_pointer_t)bkt.weak_key, (const_any_pointer_t)bkt.weak_value, context); #endif -#if CFSet || CFBag - INVOKE_CALLBACK2(applier, (const_any_pointer_t)keys[idx], context); +#if CFSet + INVOKE_CALLBACK2(applier, (const_any_pointer_t)bkt.weak_value, context); #endif +#if CFBag + for (CFIndex cnt = bkt.count; cnt--;) { + INVOKE_CALLBACK2(applier, (const_any_pointer_t)bkt.weak_value, context); } - } - } +#endif + return (Boolean)true; + }); } -static void __CFSetGrow(CFMutableHashRef hc, CFIndex numNewValues) { - any_t *oldkeys = hc->_keys; - any_t *oldvalues = hc->_values; - CFIndex nbuckets = hc->_bucketsNum; - hc->_bucketsCap = __CFHashRoundUpCapacity(hc->_bucketsUsed + numNewValues); - hc->_bucketsNum = __CFHashNumBucketsForCapacity(hc->_bucketsCap); - hc->_deletes = 0; - CFAllocatorRef allocator = __CFGetAllocator(hc); - CFOptionFlags weakOrStrong = (hc->_xflags & __kCFHashWeakKeys) ? 0 : __kCFAllocatorGCScannedMemory; - any_t *mem = (any_t *)_CFAllocatorAllocateGC(allocator, hc->_bucketsNum * sizeof(any_t), weakOrStrong); - if (NULL == mem) __CFSetHandleOutOfMemory(hc, hc->_bucketsNum * sizeof(any_t)); - if (__CFOASafe) __CFSetLastAllocationEventName(mem, "CFSet (key-store)"); - CF_WRITE_BARRIER_BASE_ASSIGN(allocator, hc, hc->_keys, mem); - CFAllocatorRef keysAllocator = (hc->_xflags & __kCFHashWeakKeys) ? kCFAllocatorNull : allocator; // GC: avoids write-barrier in weak case. - any_t *keysBase = mem; -#if CFDictionary || CFBag - weakOrStrong = (hc->_xflags & __kCFHashWeakValues) ? 0 : __kCFAllocatorGCScannedMemory; - mem = (any_t *)_CFAllocatorAllocateGC(allocator, hc->_bucketsNum * sizeof(any_t), weakOrStrong); - if (NULL == mem) __CFSetHandleOutOfMemory(hc, hc->_bucketsNum * sizeof(any_t)); - if (__CFOASafe) __CFSetLastAllocationEventName(mem, "CFSet (value-store)"); - CF_WRITE_BARRIER_BASE_ASSIGN(allocator, hc, hc->_values, mem); -#endif -#if CFDictionary - CFAllocatorRef valuesAllocator = (hc->_xflags & __kCFHashWeakValues) ? kCFAllocatorNull : allocator; // GC: avoids write-barrier in weak case. - any_t *valuesBase = mem; -#endif - for (CFIndex idx = 0, nbuckets = hc->_bucketsNum; idx < nbuckets; idx++) { - hc->_keys[idx] = hc->_marker; -#if CFDictionary || CFBag - hc->_values[idx] = 0; -#endif - } - if (NULL == oldkeys) return; - for (CFIndex idx = 0; idx < nbuckets; idx++) { - if (__CFHashKeyIsValue(hc, oldkeys[idx])) { - CFIndex match, nomatch; - __CFSetFindBuckets2(hc, oldkeys[idx], &match, &nomatch); - CFAssert3(kCFNotFound == match, __kCFLogAssertion, "%s(): two values (%p, %p) now hash to the same slot; mutable value changed while in table or hash value is not immutable", __PRETTY_FUNCTION__, oldkeys[idx], hc->_keys[match]); - if (kCFNotFound != nomatch) { - CF_WRITE_BARRIER_BASE_ASSIGN(keysAllocator, keysBase, hc->_keys[nomatch], oldkeys[idx]); -#if CFDictionary - CF_WRITE_BARRIER_BASE_ASSIGN(valuesAllocator, valuesBase, hc->_values[nomatch], oldvalues[idx]); -#endif -#if CFBag - hc->_values[nomatch] = oldvalues[idx]; -#endif - } - } - } - _CFAllocatorDeallocateGC(allocator, oldkeys); - _CFAllocatorDeallocateGC(allocator, oldvalues); +// This function is for Foundation's benefit; no one else should use it. +CF_EXPORT unsigned long _CFSetFastEnumeration(CFHashRef hc, struct __objcFastEnumerationStateEquivalent *state, void *stackbuffer, unsigned long count) { + if (CF_IS_OBJC(__kCFSetTypeID, hc)) return 0; + __CFGenericValidateType(hc, __kCFSetTypeID); + return __CFBasicHashFastEnumeration((CFBasicHashRef)hc, (struct __objcFastEnumerationStateEquivalent2 *)state, stackbuffer, count); } // This function is for Foundation's benefit; no one else should use it. -void _CFSetSetCapacity(CFMutableHashRef hc, CFIndex cap) { - if (CF_IS_OBJC(__kCFHashTypeID, hc)) return; - __CFGenericValidateType(hc, __kCFHashTypeID); - CFAssert1(__CFHashGetType(hc) != __kCFHashImmutable, __kCFLogAssertion, "%s(): collection is immutable", __PRETTY_FUNCTION__); - CFAssert3(hc->_bucketsUsed <= cap, __kCFLogAssertion, "%s(): desired capacity (%ld) is less than bucket count (%ld)", __PRETTY_FUNCTION__, cap, hc->_bucketsUsed); - __CFSetGrow(hc, cap - hc->_bucketsUsed); +CF_EXPORT Boolean _CFSetIsMutable(CFHashRef hc) { + if (CF_IS_OBJC(__kCFSetTypeID, hc)) return false; + __CFGenericValidateType(hc, __kCFSetTypeID); + return CFBasicHashIsMutable((CFBasicHashRef)hc); } +// This function is for Foundation's benefit; no one else should use it. +CF_EXPORT void _CFSetSetCapacity(CFMutableHashRef hc, CFIndex cap) { + if (CF_IS_OBJC(__kCFSetTypeID, hc)) return; + __CFGenericValidateType(hc, __kCFSetTypeID); + CFAssert2(CFBasicHashIsMutable((CFBasicHashRef)hc), __kCFLogAssertion, "%s(): immutable collection %p passed to mutating operation", __PRETTY_FUNCTION__, hc); + CFAssert3(CFSetGetCount(hc) <= cap, __kCFLogAssertion, "%s(): desired capacity (%ld) is less than count (%ld)", __PRETTY_FUNCTION__, cap, CFSetGetCount(hc)); + CFBasicHashSetCapacity((CFBasicHashRef)hc, cap); +} + +CF_INLINE CFIndex __CFSetGetKVOBit(CFHashRef hc) { + return __CFBitfieldGetValue(((CFRuntimeBase *)hc)->_cfinfo[CF_INFO_BITS], 0, 0); +} + +CF_INLINE void __CFSetSetKVOBit(CFHashRef hc, CFIndex bit) { + __CFBitfieldSetValue(((CFRuntimeBase *)hc)->_cfinfo[CF_INFO_BITS], 0, 0, ((uintptr_t)bit & 0x1)); +} + +// This function is for Foundation's benefit; no one else should use it. +CF_EXPORT CFIndex _CFSetGetKVOBit(CFHashRef hc) { + return __CFSetGetKVOBit(hc); +} + +// This function is for Foundation's benefit; no one else should use it. +CF_EXPORT void _CFSetSetKVOBit(CFHashRef hc, CFIndex bit) { + __CFSetSetKVOBit(hc, bit); +} + + +#if !defined(CF_OBJC_KVO_WILLCHANGE) +#define CF_OBJC_KVO_WILLCHANGE(obj, key) +#define CF_OBJC_KVO_DIDCHANGE(obj, key) +#define CF_OBJC_KVO_WILLCHANGEALL(obj) +#define CF_OBJC_KVO_DIDCHANGEALL(obj) +#endif #if CFDictionary void CFSetAddValue(CFMutableHashRef hc, const_any_pointer_t key, const_any_pointer_t value) { #endif #if CFSet || CFBag void CFSetAddValue(CFMutableHashRef hc, const_any_pointer_t key) { - #define value 0 -#endif - if (CFDictionary) CF_OBJC_FUNCDISPATCH2(__kCFHashTypeID, void, hc, "_addObject:forKey:", value, key); - if (CFSet) CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID, void, hc, "addObject:", key); - __CFGenericValidateType(hc, __kCFHashTypeID); - switch (__CFHashGetType(hc)) { - case __kCFHashMutable: - if (hc->_bucketsUsed == hc->_bucketsCap || NULL == hc->_keys) { - __CFSetGrow(hc, 1); - } - break; - default: - CFAssert2(__CFHashGetType(hc) != __kCFHashImmutable, __kCFLogAssertion, "%s(): immutable collection %p passed to mutating operation", __PRETTY_FUNCTION__, hc); - break; - } - hc->_mutations++; - CFIndex match, nomatch; - __CFSetFindBuckets2(hc, (any_t)key, &match, &nomatch); - if (kCFNotFound != match) { -#if CFBag - CF_OBJC_KVO_WILLCHANGE(hc, hc->_keys[match]); - hc->_values[match]++; - hc->_count++; - CF_OBJC_KVO_DIDCHANGE(hc, hc->_keys[match]); -#endif - } else { - CFAllocatorRef allocator = __CFGetAllocator(hc); - GETNEWKEY(newKey, key); -#if CFDictionary - GETNEWVALUE(newValue); -#endif - if (__CFHashKeyIsMagic(hc, newKey)) { - __CFSetFindNewMarker(hc); - } - if (hc->_keys[nomatch] == ~hc->_marker) { - hc->_deletes--; - } - CF_OBJC_KVO_WILLCHANGE(hc, key); - CFAllocatorRef keysAllocator = (hc->_xflags & __kCFHashWeakKeys) ? kCFAllocatorNull : allocator; - CF_WRITE_BARRIER_ASSIGN(keysAllocator, hc->_keys[nomatch], newKey); -#if CFDictionary - CFAllocatorRef valuesAllocator = (hc->_xflags & __kCFHashWeakValues) ? kCFAllocatorNull : allocator; - CF_WRITE_BARRIER_ASSIGN(valuesAllocator, hc->_values[nomatch], newValue); -#endif -#if CFBag - hc->_values[nomatch] = 1; + const_any_pointer_t value = key; #endif - hc->_bucketsUsed++; - hc->_count++; - CF_OBJC_KVO_DIDCHANGE(hc, key); + if (CFDictionary) CF_OBJC_FUNCDISPATCH2(__kCFSetTypeID, void, hc, "addObject:forKey:", value, key); + if (CFSet) CF_OBJC_FUNCDISPATCH1(__kCFSetTypeID, void, hc, "addObject:", key); + __CFGenericValidateType(hc, __kCFSetTypeID); + CFAssert2(CFBasicHashIsMutable((CFBasicHashRef)hc), __kCFLogAssertion, "%s(): immutable collection %p passed to mutating operation", __PRETTY_FUNCTION__, hc); + if (!CFBasicHashIsMutable((CFBasicHashRef)hc)) { + CFLog(3, CFSTR("%s(): immutable collection %p given to mutating function"), __PRETTY_FUNCTION__, hc); } + CF_OBJC_KVO_WILLCHANGE(hc, key); + CFBasicHashAddValue((CFBasicHashRef)hc, (uintptr_t)key, (uintptr_t)value); + CF_OBJC_KVO_DIDCHANGE(hc, key); } #if CFDictionary @@ -1218,51 +597,18 @@ void CFSetReplaceValue(CFMutableHashRef hc, const_any_pointer_t key, const_any_p #endif #if CFSet || CFBag void CFSetReplaceValue(CFMutableHashRef hc, const_any_pointer_t key) { - #define value 0 -#endif - if (CFDictionary) CF_OBJC_FUNCDISPATCH2(__kCFHashTypeID, void, hc, "_replaceObject:forKey:", value, key); - if (CFSet) CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID, void, hc, "_replaceObject:", key); - __CFGenericValidateType(hc, __kCFHashTypeID); - switch (__CFHashGetType(hc)) { - case __kCFHashMutable: - break; - default: - CFAssert2(__CFHashGetType(hc) != __kCFHashImmutable, __kCFLogAssertion, "%s(): immutable collection %p passed to mutating operation", __PRETTY_FUNCTION__, hc); - break; - } - hc->_mutations++; - if (0 == hc->_bucketsUsed) return; - CFIndex match = __CFSetFindBuckets1(hc, (any_t)key); - if (kCFNotFound == match) return; - CFAllocatorRef allocator = __CFGetAllocator(hc); -#if CFSet || CFBag - GETNEWKEY(newKey, key); -#endif -#if CFDictionary - GETNEWVALUE(newValue); + const_any_pointer_t value = key; #endif - any_t oldKey = hc->_keys[match]; - CF_OBJC_KVO_WILLCHANGE(hc, oldKey); -#if CFSet || CFBag - CFAllocatorRef keysAllocator = (hc->_xflags & __kCFHashWeakKeys) ? kCFAllocatorNull : allocator; - CF_WRITE_BARRIER_ASSIGN(keysAllocator, hc->_keys[match], ~hc->_marker); - if (__CFHashKeyIsMagic(hc, newKey)) { - __CFSetFindNewMarker(hc); + if (CFDictionary) CF_OBJC_FUNCDISPATCH2(__kCFSetTypeID, void, hc, "replaceObject:forKey:", value, key); + if (CFSet) CF_OBJC_FUNCDISPATCH1(__kCFSetTypeID, void, hc, "replaceObject:", key); + __CFGenericValidateType(hc, __kCFSetTypeID); + CFAssert2(CFBasicHashIsMutable((CFBasicHashRef)hc), __kCFLogAssertion, "%s(): immutable collection %p passed to mutating operation", __PRETTY_FUNCTION__, hc); + if (!CFBasicHashIsMutable((CFBasicHashRef)hc)) { + CFLog(3, CFSTR("%s(): immutable collection %p given to mutating function"), __PRETTY_FUNCTION__, hc); } - CF_WRITE_BARRIER_ASSIGN(keysAllocator, hc->_keys[match], newKey); -#endif -#if CFDictionary - any_t oldValue = hc->_values[match]; - CFAllocatorRef valuesAllocator = (hc->_xflags & __kCFHashWeakValues) ? kCFAllocatorNull : allocator; - CF_WRITE_BARRIER_ASSIGN(valuesAllocator, hc->_values[match], newValue); -#endif - CF_OBJC_KVO_DIDCHANGE(hc, oldKey); -#if CFSet || CFBag - RELEASEKEY(oldKey); -#endif -#if CFDictionary - RELEASEVALUE(oldValue); -#endif + CF_OBJC_KVO_WILLCHANGE(hc, key); + CFBasicHashReplaceValue((CFBasicHashRef)hc, (uintptr_t)key, (uintptr_t)value); + CF_OBJC_KVO_DIDCHANGE(hc, key); } #if CFDictionary @@ -1270,198 +616,49 @@ void CFSetSetValue(CFMutableHashRef hc, const_any_pointer_t key, const_any_point #endif #if CFSet || CFBag void CFSetSetValue(CFMutableHashRef hc, const_any_pointer_t key) { - #define value 0 -#endif - if (CFDictionary) CF_OBJC_FUNCDISPATCH2(__kCFHashTypeID, void, hc, "setObject:forKey:", value, key); - if (CFSet) CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID, void, hc, "_setObject:", key); - __CFGenericValidateType(hc, __kCFHashTypeID); - switch (__CFHashGetType(hc)) { - case __kCFHashMutable: - if (hc->_bucketsUsed == hc->_bucketsCap || NULL == hc->_keys) { - __CFSetGrow(hc, 1); - } - break; - default: - CFAssert2(__CFHashGetType(hc) != __kCFHashImmutable, __kCFLogAssertion, "%s(): immutable collection %p passed to mutating operation", __PRETTY_FUNCTION__, hc); - break; - } - hc->_mutations++; - CFIndex match, nomatch; - __CFSetFindBuckets2(hc, (any_t)key, &match, &nomatch); - if (kCFNotFound == match) { - CFAllocatorRef allocator = __CFGetAllocator(hc); - GETNEWKEY(newKey, key); -#if CFDictionary - GETNEWVALUE(newValue); -#endif - if (__CFHashKeyIsMagic(hc, newKey)) { - __CFSetFindNewMarker(hc); - } - if (hc->_keys[nomatch] == ~hc->_marker) { - hc->_deletes--; - } - CF_OBJC_KVO_WILLCHANGE(hc, key); - CFAllocatorRef keysAllocator = (hc->_xflags & __kCFHashWeakKeys) ? kCFAllocatorNull : allocator; - CF_WRITE_BARRIER_ASSIGN(keysAllocator, hc->_keys[nomatch], newKey); -#if CFDictionary - CFAllocatorRef valuesAllocator = (hc->_xflags & __kCFHashWeakValues) ? kCFAllocatorNull : allocator; - CF_WRITE_BARRIER_ASSIGN(valuesAllocator, hc->_values[nomatch], newValue); -#endif -#if CFBag - hc->_values[nomatch] = 1; -#endif - hc->_bucketsUsed++; - hc->_count++; - CF_OBJC_KVO_DIDCHANGE(hc, key); - } else { - CFAllocatorRef allocator = __CFGetAllocator(hc); -#if CFSet || CFBag - GETNEWKEY(newKey, key); -#endif -#if CFDictionary - GETNEWVALUE(newValue); -#endif - any_t oldKey = hc->_keys[match]; - CF_OBJC_KVO_WILLCHANGE(hc, oldKey); -#if CFSet || CFBag - CFAllocatorRef keysAllocator = (hc->_xflags & __kCFHashWeakKeys) ? kCFAllocatorNull : allocator; - CF_WRITE_BARRIER_ASSIGN(keysAllocator, hc->_keys[match], ~hc->_marker); - if (__CFHashKeyIsMagic(hc, newKey)) { - __CFSetFindNewMarker(hc); - } - CF_WRITE_BARRIER_ASSIGN(keysAllocator, hc->_keys[match], newKey); -#endif -#if CFDictionary - any_t oldValue = hc->_values[match]; - CFAllocatorRef valuesAllocator = (hc->_xflags & __kCFHashWeakValues) ? kCFAllocatorNull : allocator; - CF_WRITE_BARRIER_ASSIGN(valuesAllocator, hc->_values[match], newValue); -#endif - CF_OBJC_KVO_DIDCHANGE(hc, oldKey); -#if CFSet || CFBag - RELEASEKEY(oldKey); -#endif -#if CFDictionary - RELEASEVALUE(oldValue); + const_any_pointer_t value = key; #endif + if (CFDictionary) CF_OBJC_FUNCDISPATCH2(__kCFSetTypeID, void, hc, "setObject:forKey:", value, key); + if (CFSet) CF_OBJC_FUNCDISPATCH1(__kCFSetTypeID, void, hc, "_setObject:", key); + __CFGenericValidateType(hc, __kCFSetTypeID); + CFAssert2(CFBasicHashIsMutable((CFBasicHashRef)hc), __kCFLogAssertion, "%s(): immutable collection %p passed to mutating operation", __PRETTY_FUNCTION__, hc); + if (!CFBasicHashIsMutable((CFBasicHashRef)hc)) { + CFLog(3, CFSTR("%s(): immutable collection %p given to mutating function"), __PRETTY_FUNCTION__, hc); } + CF_OBJC_KVO_WILLCHANGE(hc, key); +//#warning this for a dictionary used to not replace the key + CFBasicHashSetValue((CFBasicHashRef)hc, (uintptr_t)key, (uintptr_t)value); + CF_OBJC_KVO_DIDCHANGE(hc, key); } void CFSetRemoveValue(CFMutableHashRef hc, const_any_pointer_t key) { - if (CFDictionary) CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID, void, hc, "removeObjectForKey:", key); - if (CFSet) CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID, void, hc, "removeObject:", key); - __CFGenericValidateType(hc, __kCFHashTypeID); - switch (__CFHashGetType(hc)) { - case __kCFHashMutable: - break; - default: - CFAssert2(__CFHashGetType(hc) != __kCFHashImmutable, __kCFLogAssertion, "%s(): immutable collection %p passed to mutating operation", __PRETTY_FUNCTION__, hc); - break; - } - hc->_mutations++; - if (0 == hc->_bucketsUsed) return; - CFIndex match = __CFSetFindBuckets1(hc, (any_t)key); - if (kCFNotFound == match) return; - if (1 < __CFHashGetOccurrenceCount(hc, match)) { -#if CFBag - CF_OBJC_KVO_WILLCHANGE(hc, hc->_keys[match]); - hc->_values[match]--; - hc->_count--; - CF_OBJC_KVO_DIDCHANGE(hc, hc->_keys[match]); -#endif - } else { - CFAllocatorRef allocator = __CFGetAllocator(hc); - any_t oldKey = hc->_keys[match]; - CF_OBJC_KVO_WILLCHANGE(hc, oldKey); - CFAllocatorRef keysAllocator = (hc->_xflags & __kCFHashWeakKeys) ? kCFAllocatorNull : allocator; - CF_WRITE_BARRIER_ASSIGN(keysAllocator, hc->_keys[match], ~hc->_marker); -#if CFDictionary - any_t oldValue = hc->_values[match]; - CFAllocatorRef valuesAllocator = (hc->_xflags & __kCFHashWeakValues) ? kCFAllocatorNull : allocator; - CF_WRITE_BARRIER_ASSIGN(valuesAllocator, hc->_values[match], 0); -#endif -#if CFBag - hc->_values[match] = 0; -#endif - hc->_count--; - hc->_bucketsUsed--; - hc->_deletes++; - CF_OBJC_KVO_DIDCHANGE(hc, oldKey); - RELEASEKEY(oldKey); -#if CFDictionary - RELEASEVALUE(oldValue); -#endif - if (__CFSetShouldShrink(hc)) { - __CFSetGrow(hc, 0); - } else { - // When the probeskip == 1 always and only, a DELETED slot followed by an EMPTY slot - // can be converted to an EMPTY slot. By extension, a chain of DELETED slots followed - // by an EMPTY slot can be converted to EMPTY slots, which is what we do here. - if (match < hc->_bucketsNum - 1 && hc->_keys[match + 1] == hc->_marker) { - while (0 <= match && hc->_keys[match] == ~hc->_marker) { - hc->_keys[match] = hc->_marker; - hc->_deletes--; - match--; - } - } - } + if (CFDictionary) CF_OBJC_FUNCDISPATCH1(__kCFSetTypeID, void, hc, "removeObjectForKey:", key); + if (CFSet) CF_OBJC_FUNCDISPATCH1(__kCFSetTypeID, void, hc, "removeObject:", key); + __CFGenericValidateType(hc, __kCFSetTypeID); + CFAssert2(CFBasicHashIsMutable((CFBasicHashRef)hc), __kCFLogAssertion, "%s(): immutable collection %p passed to mutating operation", __PRETTY_FUNCTION__, hc); + if (!CFBasicHashIsMutable((CFBasicHashRef)hc)) { + CFLog(3, CFSTR("%s(): immutable collection %p given to mutating function"), __PRETTY_FUNCTION__, hc); } + CF_OBJC_KVO_WILLCHANGE(hc, key); + CFBasicHashRemoveValue((CFBasicHashRef)hc, (uintptr_t)key); + CF_OBJC_KVO_DIDCHANGE(hc, key); } void CFSetRemoveAllValues(CFMutableHashRef hc) { - if (CFDictionary) CF_OBJC_FUNCDISPATCH0(__kCFHashTypeID, void, hc, "removeAllObjects"); - if (CFSet) CF_OBJC_FUNCDISPATCH0(__kCFHashTypeID, void, hc, "removeAllObjects"); - __CFGenericValidateType(hc, __kCFHashTypeID); - switch (__CFHashGetType(hc)) { - case __kCFHashMutable: - break; - default: - CFAssert2(__CFHashGetType(hc) != __kCFHashImmutable, __kCFLogAssertion, "%s(): immutable collection %p passed to mutating operation", __PRETTY_FUNCTION__, hc); - break; - } - hc->_mutations++; - if (0 == hc->_bucketsUsed) return; - CFAllocatorRef allocator = __CFGetAllocator(hc); - any_t *keys = hc->_keys; - for (CFIndex idx = 0, nbuckets = hc->_bucketsNum; idx < nbuckets; idx++) { - if (__CFHashKeyIsValue(hc, keys[idx])) { - any_t oldKey = keys[idx]; - CF_OBJC_KVO_WILLCHANGE(hc, oldKey); -#if CFDictionary || CFSet - hc->_count--; -#endif -#if CFBag - hc->_count -= hc->_values[idx]; -#endif - CFAllocatorRef keysAllocator = (hc->_xflags & __kCFHashWeakKeys) ? kCFAllocatorNull : allocator; - CF_WRITE_BARRIER_ASSIGN(keysAllocator, hc->_keys[idx], ~hc->_marker); -#if CFDictionary - any_t oldValue = hc->_values[idx]; - CFAllocatorRef valuesAllocator = (hc->_xflags & __kCFHashWeakValues) ? kCFAllocatorNull : allocator; - CF_WRITE_BARRIER_ASSIGN(valuesAllocator, hc->_values[idx], 0); -#endif -#if CFBag - hc->_values[idx] = 0; -#endif - hc->_bucketsUsed--; - hc->_deletes++; - CF_OBJC_KVO_DIDCHANGE(hc, oldKey); - RELEASEKEY(oldKey); -#if CFDictionary - RELEASEVALUE(oldValue); -#endif - } - } - for (CFIndex idx = 0, nbuckets = hc->_bucketsNum; idx < nbuckets; idx++) { - keys[idx] = hc->_marker; - } - hc->_deletes = 0; - hc->_bucketsUsed = 0; - hc->_count = 0; - if (__CFSetShouldShrink(hc) && (256 <= hc->_bucketsCap)) { - __CFSetGrow(hc, 128); + if (CFDictionary) CF_OBJC_FUNCDISPATCH0(__kCFSetTypeID, void, hc, "removeAllObjects"); + if (CFSet) CF_OBJC_FUNCDISPATCH0(__kCFSetTypeID, void, hc, "removeAllObjects"); + __CFGenericValidateType(hc, __kCFSetTypeID); + CFAssert2(CFBasicHashIsMutable((CFBasicHashRef)hc), __kCFLogAssertion, "%s(): immutable collection %p passed to mutating operation", __PRETTY_FUNCTION__, hc); + if (!CFBasicHashIsMutable((CFBasicHashRef)hc)) { + CFLog(3, CFSTR("%s(): immutable collection %p given to mutating function"), __PRETTY_FUNCTION__, hc); } + CF_OBJC_KVO_WILLCHANGEALL(hc); + CFBasicHashRemoveAllValues((CFBasicHashRef)hc); + CF_OBJC_KVO_DIDCHANGEALL(hc); } #undef CF_OBJC_KVO_WILLCHANGE #undef CF_OBJC_KVO_DIDCHANGE +#undef CF_OBJC_KVO_WILLCHANGEALL +#undef CF_OBJC_KVO_DIDCHANGEALL