]> git.saurik.com Git - apple/cf.git/blobdiff - CFBag.c
CF-635.15.tar.gz
[apple/cf.git] / CFBag.c
diff --git a/CFBag.c b/CFBag.c
index facf851ee8e82b9958a1f817d4034bd3b39e3647..5da22be6b6d5527ac9145d87b6e67f39caaa74c5 100644 (file)
--- a/CFBag.c
+++ b/CFBag.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -22,7 +22,7 @@
  */
 
 /*     CFBag.c
-       Copyright 1998-2008, Apple, Inc. All rights reserved.
+       Copyright (c) 1998-2011, Apple Inc. All rights reserved.
        Responsibility: Christopher Kane
        Machine generated from Notes/HashingCode.template
 */
@@ -46,6 +46,7 @@
 const CFBagKeyCallBacks kCFTypeBagKeyCallBacks = {0, __CFTypeCollectionRetain, __CFTypeCollectionRelease, CFCopyDescription, CFEqual, CFHash};
 const CFBagKeyCallBacks kCFCopyStringBagKeyCallBacks = {0, __CFStringCollectionCopy, __CFTypeCollectionRelease, CFCopyDescription, CFEqual, CFHash};
 const CFBagValueCallBacks kCFTypeBagValueCallBacks = {0, __CFTypeCollectionRetain, __CFTypeCollectionRelease, CFCopyDescription, CFEqual};
+__private_extern__ const CFBagValueCallBacks kCFTypeBagValueCompactableCallBacks = {0, __CFTypeCollectionRetain, __CFTypeCollectionRelease, CFCopyDescription, CFEqual};
 static const CFBagKeyCallBacks __kCFNullBagKeyCallBacks = {0, NULL, NULL, NULL, NULL, NULL};
 static const CFBagValueCallBacks __kCFNullBagValueCallBacks = {0, NULL, NULL, NULL, NULL};
 
@@ -131,95 +132,232 @@ CFTypeID CFBagGetTypeID(void) {
     return __kCFBagTypeID;
 }
 
-static uintptr_t __CFBagCallback(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);
+#define GCRETAIN(A, B) kCFTypeSetCallBacks.retain(A, B)
+#define GCRELEASE(A, B) kCFTypeSetCallBacks.release(A, B)
+
+static uintptr_t __CFBagStandardRetainValue(CFConstBasicHashRef ht, uintptr_t stack_value) {
+    if (CFBasicHashGetSpecialBits(ht) & 0x0100) return stack_value;
+    return (CFBasicHashHasStrongValues(ht)) ? (uintptr_t)GCRETAIN(kCFAllocatorSystemDefault, (CFTypeRef)stack_value) : (uintptr_t)CFRetain((CFTypeRef)stack_value);
+}
+
+static uintptr_t __CFBagStandardRetainKey(CFConstBasicHashRef ht, uintptr_t stack_key) {
+    if (CFBasicHashGetSpecialBits(ht) & 0x0001) return stack_key;
+    return (CFBasicHashHasStrongKeys(ht)) ? (uintptr_t)GCRETAIN(kCFAllocatorSystemDefault, (CFTypeRef)stack_key) : (uintptr_t)CFRetain((CFTypeRef)stack_key);
+}
+
+static void __CFBagStandardReleaseValue(CFConstBasicHashRef ht, uintptr_t stack_value) {
+    if (CFBasicHashGetSpecialBits(ht) & 0x0200) return;
+    if (CFBasicHashHasStrongValues(ht)) GCRELEASE(kCFAllocatorSystemDefault, (CFTypeRef)stack_value); else CFRelease((CFTypeRef)stack_value);
+}
+
+static void __CFBagStandardReleaseKey(CFConstBasicHashRef ht, uintptr_t stack_key) {
+    if (CFBasicHashGetSpecialBits(ht) & 0x0002) return;
+    if (CFBasicHashHasStrongKeys(ht)) GCRELEASE(kCFAllocatorSystemDefault, (CFTypeRef)stack_key); else CFRelease((CFTypeRef)stack_key);
+}
+
+static Boolean __CFBagStandardEquateValues(CFConstBasicHashRef ht, uintptr_t coll_value1, uintptr_t stack_value2) {
+    if (CFBasicHashGetSpecialBits(ht) & 0x0400) return coll_value1 == stack_value2;
+    return CFEqual((CFTypeRef)coll_value1, (CFTypeRef)stack_value2);
+}
+
+static Boolean __CFBagStandardEquateKeys(CFConstBasicHashRef ht, uintptr_t coll_key1, uintptr_t stack_key2) {
+    if (CFBasicHashGetSpecialBits(ht) & 0x0004) return coll_key1 == stack_key2;
+    return CFEqual((CFTypeRef)coll_key1, (CFTypeRef)stack_key2);
+}
+
+static uintptr_t __CFBagStandardHashKey(CFConstBasicHashRef ht, uintptr_t stack_key) {
+    if (CFBasicHashGetSpecialBits(ht) & 0x0008) return stack_key;
+    return (uintptr_t)CFHash((CFTypeRef)stack_key);
+}
+
+static uintptr_t __CFBagStandardGetIndirectKey(CFConstBasicHashRef ht, uintptr_t coll_value) {
+    return 0;
+}
+
+static CFStringRef __CFBagStandardCopyValueDescription(CFConstBasicHashRef ht, uintptr_t stack_value) {
+    if (CFBasicHashGetSpecialBits(ht) & 0x0800) return CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<%p>"), (void *)stack_value);
+    return CFCopyDescription((CFTypeRef)stack_value);
+}
+
+static CFStringRef __CFBagStandardCopyKeyDescription(CFConstBasicHashRef ht, uintptr_t stack_key) {
+    if (CFBasicHashGetSpecialBits(ht) & 0x0010) return CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<%p>"), (void *)stack_key);
+    return CFCopyDescription((CFTypeRef)stack_key);
+}
+
+static CFBasicHashCallbacks *__CFBagStandardCopyCallbacks(CFConstBasicHashRef ht, CFAllocatorRef allocator, CFBasicHashCallbacks *cb);
+static void __CFBagStandardFreeCallbacks(CFConstBasicHashRef ht, CFAllocatorRef allocator, CFBasicHashCallbacks *cb);
+
+static const CFBasicHashCallbacks CFBagStandardCallbacks = {
+    __CFBagStandardCopyCallbacks,
+    __CFBagStandardFreeCallbacks,
+    __CFBagStandardRetainValue,
+    __CFBagStandardRetainKey,
+    __CFBagStandardReleaseValue,
+    __CFBagStandardReleaseKey,
+    __CFBagStandardEquateValues,
+    __CFBagStandardEquateKeys,
+    __CFBagStandardHashKey,
+    __CFBagStandardGetIndirectKey,
+    __CFBagStandardCopyValueDescription,
+    __CFBagStandardCopyKeyDescription
+};
+
+static CFBasicHashCallbacks *__CFBagStandardCopyCallbacks(CFConstBasicHashRef ht, CFAllocatorRef allocator, CFBasicHashCallbacks *cb) {
+    return (CFBasicHashCallbacks *)&CFBagStandardCallbacks;
+}
+
+static void __CFBagStandardFreeCallbacks(CFConstBasicHashRef ht, CFAllocatorRef allocator, CFBasicHashCallbacks *cb) {
+}
+    
+
+static CFBasicHashCallbacks *__CFBagCopyCallbacks(CFConstBasicHashRef ht, CFAllocatorRef allocator, CFBasicHashCallbacks *cb) {
+    CFBasicHashCallbacks *newcb = NULL;
+    if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) {
+        newcb = (CFBasicHashCallbacks *)auto_zone_allocate_object(objc_collectableZone(), sizeof(CFBasicHashCallbacks) + 10 * sizeof(void *), AUTO_MEMORY_UNSCANNED, false, false);
+    } else {
+        newcb = (CFBasicHashCallbacks *)CFAllocatorAllocate(allocator, sizeof(CFBasicHashCallbacks) + 10 * sizeof(void *), 0);
     }
+    if (!newcb) HALT;
+    memmove(newcb, (void *)cb, sizeof(CFBasicHashCallbacks) + 10 * sizeof(void *));
+    return newcb;
+}
+
+static void __CFBagFreeCallbacks(CFConstBasicHashRef ht, CFAllocatorRef allocator, CFBasicHashCallbacks *cb) {
+    if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) {
+    } else {
+       CFAllocatorDeallocate(allocator, cb);
     }
+}
+    
+static uintptr_t __CFBagRetainValue(CFConstBasicHashRef ht, uintptr_t stack_value) {
+    const CFBasicHashCallbacks *cb = CFBasicHashGetCallbacks(ht);
+    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 stack_value;
+    return (uintptr_t)INVOKE_CALLBACK2(value_retain, CFGetAllocator(ht), (const_any_pointer_t)stack_value);
+}
+
+static uintptr_t __CFBagRetainKey(CFConstBasicHashRef ht, uintptr_t stack_key) {
+    const CFBasicHashCallbacks *cb = CFBasicHashGetCallbacks(ht);
+    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 stack_key;
+    return (uintptr_t)INVOKE_CALLBACK2(key_retain, CFGetAllocator(ht), (const_any_pointer_t)stack_key);
+}
+
+static void __CFBagReleaseValue(CFConstBasicHashRef ht, uintptr_t stack_value) {
+    const CFBasicHashCallbacks *cb = CFBasicHashGetCallbacks(ht);
+    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) stack_value);
+}
+
+static void __CFBagReleaseKey(CFConstBasicHashRef ht, uintptr_t stack_key) {
+    const CFBasicHashCallbacks *cb = CFBasicHashGetCallbacks(ht);
+    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) stack_key);
+}
+
+static Boolean __CFBagEquateValues(CFConstBasicHashRef ht, uintptr_t coll_value1, uintptr_t stack_value2) {
+    const CFBasicHashCallbacks *cb = CFBasicHashGetCallbacks(ht);
+    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 (coll_value1 == stack_value2);
+    return INVOKE_CALLBACK2(value_equal, (const_any_pointer_t) coll_value1, (const_any_pointer_t) stack_value2) ? 1 : 0;
+}
+
+static Boolean __CFBagEquateKeys(CFConstBasicHashRef ht, uintptr_t coll_key1, uintptr_t stack_key2) {
+    const CFBasicHashCallbacks *cb = CFBasicHashGetCallbacks(ht);
+    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 (coll_key1 == stack_key2);
+    return INVOKE_CALLBACK2(key_equal, (const_any_pointer_t) coll_key1, (const_any_pointer_t) stack_key2) ? 1 : 0;
+}
+
+static uintptr_t __CFBagHashKey(CFConstBasicHashRef ht, uintptr_t stack_key) {
+    const CFBasicHashCallbacks *cb = CFBasicHashGetCallbacks(ht);
+    CFHashCode (*hash)(const_any_pointer_t) = (CFHashCode (*)(const_any_pointer_t))cb->context[6];
+    if (NULL == hash) return stack_key;
+    return (uintptr_t)INVOKE_CALLBACK1(hash, (const_any_pointer_t) stack_key);
+}
+
+static uintptr_t __CFBagGetIndirectKey(CFConstBasicHashRef ht, uintptr_t coll_value) {
     return 0;
 }
 
-static CFBasicHashRef __CFBagCreateGeneric(CFAllocatorRef allocator, const CFHashKeyCallBacks *keyCallBacks, const CFHashValueCallBacks *valueCallBacks, Boolean useValueCB) {
+static CFStringRef __CFBagCopyValueDescription(CFConstBasicHashRef ht, uintptr_t stack_value) {
+    const CFBasicHashCallbacks *cb = CFBasicHashGetCallbacks(ht);
+    CFStringRef (*value_describe)(const_any_pointer_t) = (CFStringRef (*)(const_any_pointer_t))cb->context[8];
+    if (NULL == value_describe) return CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<%p>"), (const_any_pointer_t) stack_value);
+    return (CFStringRef)INVOKE_CALLBACK1(value_describe, (const_any_pointer_t) stack_value);
+}
 
-    CFBasicHashCallbacks *cb = NULL;
+static CFStringRef __CFBagCopyKeyDescription(CFConstBasicHashRef ht, uintptr_t stack_key) {
+    const CFBasicHashCallbacks *cb = CFBasicHashGetCallbacks(ht);
+    CFStringRef (*key_describe)(const_any_pointer_t) = (CFStringRef (*)(const_any_pointer_t))cb->context[9];
+    if (NULL == key_describe) return CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<%p>"), (const_any_pointer_t) stack_key);
+    return (CFStringRef)INVOKE_CALLBACK1(key_describe, (const_any_pointer_t) stack_key);
+}
+
+static CFBasicHashRef __CFBagCreateGeneric(CFAllocatorRef allocator, const CFHashKeyCallBacks *keyCallBacks, const CFHashValueCallBacks *valueCallBacks, Boolean useValueCB) {
     CFOptionFlags flags = kCFBasicHashLinearHashing; // kCFBasicHashExponentialHashing
     flags |= (CFDictionary ? kCFBasicHashHasKeys : 0) | (CFBag ? kCFBasicHashHasCounts : 0);
 
+    CFBasicHashCallbacks *cb = NULL;
+    Boolean std_cb = false;
+    uint16_t specialBits = 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(&__kCFNullBagKeyCallBacks, keyCallBacks, sizeof(__kCFNullBagKeyCallBacks))))
-                && (!useValueCB || (NULL == valueCallBacks || (valueCallBacks && 0 == memcmp(&__kCFNullBagValueCallBacks, valueCallBacks, sizeof(__kCFNullBagValueCallBacks)))))) {
-        cb = (CFBasicHashCallbacks *)& CFBasicHashNullCallbacks;
-    } else if ((&kCFTypeBagKeyCallBacks == keyCallBacks || (keyCallBacks && 0 == memcmp(&kCFTypeBagKeyCallBacks, keyCallBacks, sizeof(kCFTypeBagKeyCallBacks))))
-                && (!useValueCB || (&kCFTypeBagValueCallBacks == valueCallBacks || (valueCallBacks && 0 == memcmp(&kCFTypeBagValueCallBacks, valueCallBacks, sizeof(kCFTypeBagValueCallBacks)))))) {
-        std_cb = true;
-        cb = (CFBasicHashCallbacks *)& CFBasicHashStandardCallbacks;
-    } else {
+
+    if ((NULL == keyCallBacks || 0 == keyCallBacks->version) && (!useValueCB || NULL == valueCallBacks || 0 == valueCallBacks->version)) {
+        Boolean keyRetainNull = NULL == keyCallBacks || NULL == keyCallBacks->retain;
+        Boolean keyReleaseNull = NULL == keyCallBacks || NULL == keyCallBacks->release;
+        Boolean keyEquateNull = NULL == keyCallBacks || NULL == keyCallBacks->equal;
+        Boolean keyHashNull = NULL == keyCallBacks || NULL == keyCallBacks->hash;
+        Boolean keyDescribeNull = NULL == keyCallBacks || NULL == keyCallBacks->copyDescription;
+
+        Boolean valueRetainNull = (useValueCB && (NULL == valueCallBacks || NULL == valueCallBacks->retain)) || (!useValueCB && keyRetainNull);
+        Boolean valueReleaseNull = (useValueCB && (NULL == valueCallBacks || NULL == valueCallBacks->release)) || (!useValueCB && keyReleaseNull);
+        Boolean valueEquateNull = (useValueCB && (NULL == valueCallBacks || NULL == valueCallBacks->equal)) || (!useValueCB && keyEquateNull);
+        Boolean valueDescribeNull = (useValueCB && (NULL == valueCallBacks || NULL == valueCallBacks->copyDescription)) || (!useValueCB && keyDescribeNull);
+
+        Boolean keyRetainStd = keyRetainNull || __CFTypeCollectionRetain == keyCallBacks->retain;
+        Boolean keyReleaseStd = keyReleaseNull || __CFTypeCollectionRelease == keyCallBacks->release;
+        Boolean keyEquateStd = keyEquateNull || CFEqual == keyCallBacks->equal;
+        Boolean keyHashStd = keyHashNull || CFHash == keyCallBacks->hash;
+        Boolean keyDescribeStd = keyDescribeNull || CFCopyDescription == keyCallBacks->copyDescription;
+
+        Boolean valueRetainStd = (useValueCB && (valueRetainNull || __CFTypeCollectionRetain == valueCallBacks->retain)) || (!useValueCB && keyRetainStd);
+        Boolean valueReleaseStd = (useValueCB && (valueReleaseNull || __CFTypeCollectionRelease == valueCallBacks->release)) || (!useValueCB && keyReleaseStd);
+        Boolean valueEquateStd = (useValueCB && (valueEquateNull || CFEqual == valueCallBacks->equal)) || (!useValueCB && keyEquateStd);
+        Boolean valueDescribeStd = (useValueCB && (valueDescribeNull || CFCopyDescription == valueCallBacks->copyDescription)) || (!useValueCB && keyDescribeStd);
+
+        if (keyRetainStd && keyReleaseStd && keyEquateStd && keyHashStd && keyDescribeStd && valueRetainStd && valueReleaseStd && valueEquateStd && valueDescribeStd) {
+            cb = (CFBasicHashCallbacks *)&CFBagStandardCallbacks;
+            if (!(keyRetainNull || keyReleaseNull || keyEquateNull || keyHashNull || keyDescribeNull || valueRetainNull || valueReleaseNull || valueEquateNull || valueDescribeNull)) {
+                std_cb = true;
+            } else {
+                // just set these to tickle the GC Strong logic below in a way that mimics past practice
+                key_retain = keyCallBacks ? keyCallBacks->retain : NULL;
+                key_release = keyCallBacks ? keyCallBacks->release : NULL;
+                if (useValueCB) {
+                    value_retain = valueCallBacks ? valueCallBacks->retain : NULL;
+                    value_release = valueCallBacks ? valueCallBacks->release : NULL;
+                } else {
+                    value_retain = key_retain;
+                    value_release = key_release;
+                }
+            }
+            if (keyRetainNull) specialBits |= 0x0001;
+            if (keyReleaseNull) specialBits |= 0x0002;
+            if (keyEquateNull) specialBits |= 0x0004;
+            if (keyHashNull) specialBits |= 0x0008;
+            if (keyDescribeNull) specialBits |= 0x0010;
+            if (valueRetainNull) specialBits |= 0x0100;
+            if (valueReleaseNull) specialBits |= 0x0200;
+            if (valueEquateNull) specialBits |= 0x0400;
+            if (valueDescribeNull) specialBits |= 0x0800;
+        }
+    }
+
+    if (!cb) {
         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;
@@ -241,24 +379,26 @@ static CFBasicHashRef __CFBagCreateGeneric(CFAllocatorRef allocator, const CFHas
             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);
+            newcb = (CFBasicHashCallbacks *)auto_zone_allocate_object(objc_collectableZone(), sizeof(CFBasicHashCallbacks) + 10 * sizeof(void *), AUTO_MEMORY_UNSCANNED, false, false);
         } else {
-            newcb = (CFBasicHashCallbacks *)CFAllocatorAllocate(allocator, 10 * sizeof(void *), 0);
+            newcb = (CFBasicHashCallbacks *)CFAllocatorAllocate(allocator, sizeof(CFBasicHashCallbacks) + 10 * sizeof(void *), 0);
         }
         if (!newcb) HALT;
-        newcb->func = (CFBasicHashCallbackType)__CFBagCallback;
+        newcb->copyCallbacks = __CFBagCopyCallbacks;
+        newcb->freeCallbacks = __CFBagFreeCallbacks;
+        newcb->retainValue = __CFBagRetainValue;
+        newcb->retainKey = __CFBagRetainKey;
+        newcb->releaseValue = __CFBagReleaseValue;
+        newcb->releaseKey = __CFBagReleaseKey;
+        newcb->equateValues = __CFBagEquateValues;
+        newcb->equateKeys = __CFBagEquateKeys;
+        newcb->hashKey = __CFBagHashKey;
+        newcb->getIndirectKey = __CFBagGetIndirectKey;
+        newcb->copyValueDescription = __CFBagCopyValueDescription;
+        newcb->copyKeyDescription = __CFBagCopyKeyDescription;
         newcb->context[0] = (uintptr_t)value_retain;
         newcb->context[1] = (uintptr_t)key_retain;
         newcb->context[2] = (uintptr_t)value_release;
@@ -266,8 +406,8 @@ static CFBasicHashRef __CFBagCreateGeneric(CFAllocatorRef allocator, const CFHas
         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;
+        newcb->context[8] = (uintptr_t)value_describe;
+        newcb->context[9] = (uintptr_t)key_describe;
         cb = newcb;
     }
 
@@ -278,9 +418,43 @@ static CFBasicHashRef __CFBagCreateGeneric(CFAllocatorRef allocator, const CFHas
         if (std_cb || key_retain != NULL || key_release != NULL) {
             flags |= kCFBasicHashStrongKeys;
         }
+#if CFDictionary
+        if (valueCallBacks == &kCFTypeDictionaryValueCompactableCallBacks) {
+            // Foundation allocated collections will have compactable values
+            flags |= kCFBasicHashCompactableValues;
+        }
+#endif
     }
 
-    return CFBasicHashCreate(allocator, flags, cb);
+    CFBasicHashRef ht = CFBasicHashCreate(allocator, flags, cb);
+    CFBasicHashSetSpecialBits(ht, specialBits);
+    return ht;
+}
+
+#if CFDictionary
+__private_extern__ CFHashRef __CFBagCreateTransfer(CFAllocatorRef allocator, const_any_pointer_t *klist, const_any_pointer_t *vlist, CFIndex numValues) {
+#endif
+#if CFSet || CFBag
+__private_extern__ CFHashRef __CFBagCreateTransfer(CFAllocatorRef allocator, const_any_pointer_t *klist, CFIndex numValues) {
+    const_any_pointer_t *vlist = klist;
+#endif
+    CFTypeID typeID = CFBagGetTypeID();
+    CFAssert2(0 <= numValues, __kCFLogAssertion, "%s(): numValues (%ld) cannot be less than zero", __PRETTY_FUNCTION__, numValues);
+    CFOptionFlags flags = kCFBasicHashLinearHashing; // kCFBasicHashExponentialHashing
+    flags |= (CFDictionary ? kCFBasicHashHasKeys : 0) | (CFBag ? kCFBasicHashHasCounts : 0);
+    CFBasicHashCallbacks *cb = (CFBasicHashCallbacks *)&CFBagStandardCallbacks;
+    CFBasicHashRef ht = CFBasicHashCreate(allocator, flags, cb);
+    CFBasicHashSetSpecialBits(ht, 0x0303);
+    if (0 < numValues) CFBasicHashSetCapacity(ht, numValues);
+    for (CFIndex idx = 0; idx < numValues; idx++) {
+        CFBasicHashAddValue(ht, (uintptr_t)klist[idx], (uintptr_t)vlist[idx]);
+    }
+    CFBasicHashSetSpecialBits(ht, 0x0000);
+    CFBasicHashMakeImmutable(ht);
+    *(uintptr_t *)ht = __CFISAForTypeID(typeID);
+    _CFRuntimeSetInstanceTypeID(ht, typeID);
+    if (__CFOASafe) __CFSetLastAllocationEventName(ht, "CFBag (immutable)");
+    return (CFHashRef)ht;
 }
 
 #if CFDictionary
@@ -429,8 +603,8 @@ const_any_pointer_t CFBagGetValue(CFHashRef hc, const_any_pointer_t key) {
 }
 
 Boolean CFBagGetValueIfPresent(CFHashRef hc, const_any_pointer_t key, const_any_pointer_t *value) {
-    if (CFDictionary) CF_OBJC_FUNCDISPATCH2(__kCFBagTypeID, Boolean, hc, "_getValue:forKey:", (any_t *)value, key);
-    if (CFSet) CF_OBJC_FUNCDISPATCH2(__kCFBagTypeID, Boolean, hc, "_getValue:forObj:", (any_t *)value, key);
+    if (CFDictionary) CF_OBJC_FUNCDISPATCH2(__kCFBagTypeID, Boolean, hc, "__getValue:forKey:", (any_t *)value, key);
+    if (CFSet) CF_OBJC_FUNCDISPATCH2(__kCFBagTypeID, Boolean, hc, "__getValue:forObj:", (any_t *)value, key);
     __CFGenericValidateType(hc, __kCFBagTypeID);
     CFBasicHashBucket bkt = CFBasicHashFindBucket((CFBasicHashRef)hc, (uintptr_t)key);
     if (0 < bkt.count) {
@@ -489,7 +663,8 @@ void CFBagGetValues(CFHashRef hc, const_any_pointer_t *keybuf) {
     __CFGenericValidateType(hc, __kCFBagTypeID);
     if (kCFUseCollectableAllocator) {
         CFOptionFlags flags = CFBasicHashGetFlags((CFBasicHashRef)hc);
-        __block const_any_pointer_t *keys = keybuf, *values = valuebuf;
+        __block const_any_pointer_t *keys = keybuf;
+        __block const_any_pointer_t *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++; }
@@ -500,14 +675,14 @@ void CFBagGetValues(CFHashRef hc, const_any_pointer_t *keybuf) {
                 return (Boolean)true;
             });
     } else {
-        CFBasicHashGetElements((CFBasicHashRef)hc, CFBagGetCount(hc), (uintptr_t *)valuebuf, NULL, (uintptr_t *)keybuf, NULL);
+        CFBasicHashGetElements((CFBasicHashRef)hc, CFBagGetCount(hc), (uintptr_t *)valuebuf, (uintptr_t *)keybuf);
     }
 }
 
 void CFBagApplyFunction(CFHashRef hc, CFBagApplierFunction applier, any_pointer_t context) {
     FAULT_CALLBACK((void **)&(applier));
-    if (CFDictionary) CF_OBJC_FUNCDISPATCH2(__kCFBagTypeID, void, hc, "_apply:context:", applier, context);
-    if (CFSet) CF_OBJC_FUNCDISPATCH2(__kCFBagTypeID, void, hc, "_applyValues:context:", applier, context);
+    if (CFDictionary) CF_OBJC_FUNCDISPATCH2(__kCFBagTypeID, void, hc, "__apply:context:", applier, context);
+    if (CFSet) CF_OBJC_FUNCDISPATCH2(__kCFBagTypeID, void, hc, "__applyValues:context:", applier, context);
     __CFGenericValidateType(hc, __kCFBagTypeID);
     CFBasicHashApply((CFBasicHashRef)hc, ^(CFBasicHashBucket bkt) {
 #if CFDictionary
@@ -620,7 +795,7 @@ void CFBagSetValue(CFMutableHashRef hc, const_any_pointer_t key) {
     const_any_pointer_t value = key;
 #endif
     if (CFDictionary) CF_OBJC_FUNCDISPATCH2(__kCFBagTypeID, void, hc, "setObject:forKey:", value, key);
-    if (CFSet) CF_OBJC_FUNCDISPATCH1(__kCFBagTypeID, void, hc, "_setObject:", key);
+    if (CFSet) CF_OBJC_FUNCDISPATCH1(__kCFBagTypeID, void, hc, "setObject:", key);
     __CFGenericValidateType(hc, __kCFBagTypeID);
     CFAssert2(CFBasicHashIsMutable((CFBasicHashRef)hc), __kCFLogAssertion, "%s(): immutable collection %p passed to mutating operation", __PRETTY_FUNCTION__, hc);
     if (!CFBasicHashIsMutable((CFBasicHashRef)hc)) {